- Memory allocation/deallocation are taking the most time.
- All the percentages for each function are very small.
The former is a characteristic of code which heavily abuses dynamic allocation. It's surprising to see how many programmers are not aware of the overhead it adds and would malloc()/free() frivolously when something simpler would suffice. This is also often accompanied by copious amounts of unnecessarily copying data around. I've worked with small embedded systems where every use of dynamic allocation would need to be justified thoroughly in code reviews; perhaps these developers would benefit from being put through the same process.
The latter is a phenomenon which arises from "excessive modularity": the functionality of the system has been split into so many little pieces that the time each function contributes to the overall total is tiny. Instead of seeing an obvious "80% of the time is being spent here" that could easily be targeted for optimisation, that 80% is scattered amongst several dozen functions each taking 1-2% each. The bottleneck isn't concentrated in one area --- the whole system is uniformly inefficient. It's extremely difficult to optimise a system like this because nothing in particular stands out as being optimisable. I've had to optimise some large Java applications that were like this, and the solution was basically to remove most of the code and rewrite it to get rid of many chains of indirection.