Pool question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • a_linux_user

    Pool question

    I am creating a large graph object in which I add nodes whenever I
    need them, and I create them by 'new node' individually. I know this
    is slow if I am going to allocate thousands of nodes individually. I
    want to replace this allocation by an allocation from a pool. One
    simple method I can think of is a manual allocation of a large array
    of nodes (since I have an estimate of how many nodes there will be),
    and use pointers to array elements, and then of course keep track of
    used nodes. I think I can do this easily because in my current version
    there is no freeing of nodes (until the end, when everything is
    freed), so it is manageable without writing a complicated pool
    mechanism. But potentially such a simplistic method will be
    inadequate. Moreover I am trying to make a transition to C++ from
    another language, so I want to know how it is done in C++ style. So I
    would like to know if there is some pool facility in the library. I
    have seen that there is a Boost pool library but I don't know if it is
    the simplest choice.
  • Kai-Uwe Bux

    #2
    Re: Pool question

    a_linux_user wrote:
    I am creating a large graph object in which I add nodes whenever I
    need them, and I create them by 'new node' individually. I know this
    is slow if I am going to allocate thousands of nodes individually. I
    want to replace this allocation by an allocation from a pool. One
    simple method I can think of is a manual allocation of a large array
    of nodes (since I have an estimate of how many nodes there will be),
    and use pointers to array elements, and then of course keep track of
    used nodes. I think I can do this easily because in my current version
    there is no freeing of nodes (until the end, when everything is
    freed), so it is manageable without writing a complicated pool
    mechanism. But potentially such a simplistic method will be
    inadequate. Moreover I am trying to make a transition to C++ from
    another language, so I want to know how it is done in C++ style. So I
    would like to know if there is some pool facility in the library. I
    have seen that there is a Boost pool library but I don't know if it is
    the simplest choice.
    First, I would change the code so that is uses an allocator instead of using
    new and delete directly. You can test the code using the standard
    allocator.

    Then I would replace that allocator with a pool allocator. You can check out
    various alternatives and also write your own. In the end, you can choose
    the fastest.


    Best

    Kai-Uwe Bux

    Comment

    • Adem

      #3
      Re: Pool question

      "a_linux_us er" <bdthatte@gmail .comwrote:
      >
      I am creating a large graph object in which I add nodes whenever I
      need them, and I create them by 'new node' individually. I know this
      is slow if I am going to allocate thousands of nodes individually. I
      want to replace this allocation by an allocation from a pool. One
      simple method I can think of is a manual allocation of a large array
      of nodes (since I have an estimate of how many nodes there will be),
      and use pointers to array elements, and then of course keep track of
      used nodes. I think I can do this easily because in my current version
      there is no freeing of nodes (until the end, when everything is
      freed), so it is manageable without writing a complicated pool
      mechanism. But potentially such a simplistic method will be
      inadequate. Moreover I am trying to make a transition to C++ from
      another language, so I want to know how it is done in C++ style. So I
      would like to know if there is some pool facility in the library. I
      have seen that there is a Boost pool library but I don't know if it is
      the simplest choice.
      Look for "operator new()" in your C++ manual(s) and on the net.
      By this mechanism you can have your own allocator.

      Comment

      • Juha Nieminen

        #4
        Re: Pool question

        a_linux_user wrote:
        I am creating a large graph object in which I add nodes whenever I
        need them, and I create them by 'new node' individually. I know this
        is slow if I am going to allocate thousands of nodes individually. I
        want to replace this allocation by an allocation from a pool.
        If all the nodes have the same size, you can use this:


        Comment

        • Stephen Horne

          #5
          Re: Pool question

          On Sun, 12 Oct 2008 12:42:13 -0700 (PDT), a_linux_user
          <bdthatte@gmail .comwrote:
          >I am creating a large graph object in which I add nodes whenever I
          >need them, and I create them by 'new node' individually. I know this
          >is slow if I am going to allocate thousands of nodes individually. I
          >want to replace this allocation by an allocation from a pool.
          Why not hold all your nodes in an std::vector, and refer to them by
          subscript?

          I've rarely felt the need for custom allocators. I usually just choose
          data structures that don't need single-item allocation.

          Comment

          • a_linux_user

            #6
            Re: Pool question

            Thanks to all of you who responded. To begin with I am going to look
            into using the standard allocator. Trying to read section 19.4 from
            Stroustrup, but so far haven't figured how to use it. Later I will try
            to post here little pieces of code to get your comments. Thank you
            once again.

            Comment

            • Juha Nieminen

              #7
              Re: Pool question

              a_linux_user wrote:
              Thanks to all of you who responded. To begin with I am going to look
              into using the standard allocator.
              I don't really understand what is it that you are going to gain from
              that. The standard allocator does 'new' and 'delete' in the way you are
              already doing.

              Comment

              • Jeff Schwab

                #8
                Re: Pool question

                a_linux_user wrote:
                Thanks to all of you who responded. To begin with I am going to look
                into using the standard allocator. Trying to read section 19.4 from
                Stroustrup, but so far haven't figured how to use it. Later I will try
                to post here little pieces of code to get your comments. Thank you
                once again.
                That may be an interesting learning exercise, but be forewarned that
                standard allocators are not used consistently by different standard
                library implementations . They're not anywhere near as useful as they
                seem at first, unless you stick with a particular STL implementation.

                Furthermore, it is often a waste of time to start optimizing constant
                factors before you even have a working program. Since you're working
                with graphs, the best places to improve performance (once your program
                functions) will probably be in your search and traversal algorithms.
                It's hard to optimize without profiling, and it's hard to profile
                without working code. Make it right before you worry about making it fast.

                My recommendation is to begin with create_node and destroy_node
                functions that just use new and delete, and typedef'd pointers that are
                either raw (e.g. typedef node* node_pointer; typedef node const*
                node_const_poin ter;) or reference-counted (e.g. typedef
                std::tr1::share d_ptr<nodenode_ pointer). If you really find that new
                and delete are your performance bottleneck down the road, you can always
                replace the use of new and delete with something fancier, without
                breaking the syntax used in the rest of your program.

                Comment

                • a_linux_user

                  #9
                  Re: Pool question

                  On Oct 13, 5:30 pm, Juha Nieminen <nos...@thanks. invalidwrote:
                  a_linux_user wrote:
                  Thanks to all of you who responded. To begin with I am going to look
                  into using the standard allocator.
                  >
                    I don't really understand what is it that you are going to gain from
                  that. The standard allocator does 'new' and 'delete' in the way you are
                  already doing.
                  Thanks for pointing this out. I didn't realize that. I was always
                  under the impression that doing 'new' for each node was somehow bad.

                  Comment

                  • Stephen Horne

                    #10
                    Re: Pool question

                    On Mon, 13 Oct 2008 13:20:09 -0700 (PDT), a_linux_user
                    <bdthatte@gmail .comwrote:
                    >On Oct 13, 5:30 pm, Juha Nieminen <nos...@thanks. invalidwrote:
                    >a_linux_user wrote:
                    Thanks to all of you who responded. To begin with I am going to look
                    into using the standard allocator.
                    >>
                    >  I don't really understand what is it that you are going to gain from
                    >that. The standard allocator does 'new' and 'delete' in the way you are
                    >already doing.
                    >
                    >Thanks for pointing this out. I didn't realize that. I was always
                    >under the impression that doing 'new' for each node was somehow bad.
                    I think this is a language issue.

                    You need to look up custom allocators. The standard allocator *is* bad
                    (for some requirements), which is why it can be overridden using
                    custom allocators.

                    Both standard and custom allocators are accessed through the new
                    operator. This is because the new operator is responsible for calling
                    the constructor - not just allocating the memory.

                    Containers have defaulted template parameters that give a kind of
                    allocation policy ("policy" being a kind of template design pattern) -
                    it may be more appropriate to target this than the new operator.

                    Comment

                    • Stephen Horne

                      #11
                      Re: Pool question

                      On Mon, 13 Oct 2008 12:45:12 -0400, Jeff Schwab
                      <jeff@schwabcen ter.comwrote:
                      >Furthermore, it is often a waste of time to start optimizing constant
                      >factors before you even have a working program.
                      Very good point. Another reason for it is that you can end up
                      overcommitted to poor algorithm/data structure choices simply because
                      you've put so much time into developing and optimising them. A
                      variation on the KISS principle, basically.

                      Comment

                      • Stephen Horne

                        #12
                        Re: Pool question

                        On Tue, 14 Oct 2008 04:20:20 +0100, Stephen Horne
                        <sh006d3592@blu eyonder.co.ukwr ote:
                        >I think this is a language issue.
                        That wasn't clear - I meant English language rather than C++. I got
                        the impression that a_linux_user was getting a tad confused.

                        Comment

                        • James Kanze

                          #13
                          Re: Pool question

                          On Oct 13, 10:20 pm, a_linux_user <bdtha...@gmail .comwrote:
                          On Oct 13, 5:30 pm, Juha Nieminen <nos...@thanks. invalidwrote:
                          a_linux_user wrote:
                          Thanks to all of you who responded. To begin with I am
                          going to look into using the standard allocator.
                          I don't really understand what is it that you are going to
                          gain from that. The standard allocator does 'new' and
                          'delete' in the way you are already doing.
                          The standard allocators are required to use the global operator
                          new() and operator delete() functions to acquire memory. They
                          do NOT use new or delete expressions, however, as they are
                          required to separate allocation an initialization.
                          Thanks for pointing this out. I didn't realize that. I was
                          always under the impression that doing 'new' for each node was
                          somehow bad.
                          What's wrong with it? It's the obvious solution, and is only
                          "bad" if it causes the program to fail to meet some requirement.

                          Also, the standard requires the standard allocator to use
                          ::operator new() and ::operator delete() to acquire and free
                          memory. However, it also explicitly states that "it is
                          unspecified when or how often this function [::operator new()]
                          is called."

                          --
                          James Kanze (GABI Software) email:james.kan ze@gmail.com
                          Conseils en informatique orientée objet/
                          Beratung in objektorientier ter Datenverarbeitu ng
                          9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

                          Comment

                          • Juha Nieminen

                            #14
                            Re: Pool question

                            James Kanze wrote:
                            What's wrong with it? It's the obvious solution, and is only
                            "bad" if it causes the program to fail to meet some requirement.
                            In many systems with many compilers the default allocator can be quite
                            slow in some situations (for example when allocating and freeing
                            enormous amounts of small objects). Using a faster allocator can speed
                            up the allocation by a large factor. If your program is very allocation
                            (and deallocation) heavy, your entire program can speed up by a large
                            factor.

                            (The most common solution to this problem is to use large arrays
                            rather than allocating each object individually, as arrays do not suffer
                            from the speed issues of 'new' and 'delete'. However, arrays cannot
                            always be used in every possible such situation.)

                            Comment

                            • a_linux_user

                              #15
                              Re: Pool question

                              On 14 Oct, 13:05, Juha Nieminen <nos...@thanks. invalidwrote:
                              James Kanze wrote:
                              What's wrong with it? It's the obvious solution, and is only
                              "bad" if it causes the program to fail to meet some requirement.
                              >
                              In many systems with many compilers the default allocator can be quite
                              slow in some situations (for example when allocating and freeing
                              enormous amounts of small objects). Using a faster allocator can speed
                              up the allocation by a large factor. If your program is very allocation
                              (and deallocation) heavy, your entire program can speed up by a large
                              factor.
                              >
                              (The most common solution to this problem is to use large arrays
                              rather than allocating each object individually, as arrays do not suffer
                              from the speed issues of 'new' and 'delete'. However, arrays cannot
                              always be used in every possible such situation.)
                              I tested two versions:
                              1. new and delete a node structure a billion times (took about 52
                              seconds)
                              2. calloc an array of million nodes, set the id of each node, then
                              free the array (and repeat this 1000 times) (took 22 seconds)
                              so clearly the second alternative does run much faster, but in my
                              graph program, where I allocate only 10 million nodes, this is not a
                              significant difference given that I am doing other computations (35
                              seconds vs 28 seconds).
                              This is what I expected, and that is what I wanted to ask about in the
                              first post. But I have to do a bit learning about various allocation
                              mechanisms available in C++ to fully understand all comments that have
                              been made above, and I want to thank you all.

                              Comment

                              Working...