Following is the piece of code which represents the bottleneck of my application:
#include <iostream>
#include <chrono>
#include <unordered_map>
#include <vector>
#include <memory>
#include <cassert>
#include <thread>
#include <random>
#include <utility>
using namespace std;
using namespace chrono;
static const size_t len = 30;
static const size_t nGraphics = 0xfffff;
static const size_t nIndexes = 600000;
static default_random_engine generator;
static normal_distribution<float> distribution(len / 2.f, 2);
struct Graphic
{
Graphic()
: lnum ((short)distribution(generator))
{
// common scenario
// most of my graphics elements belong to few layers
assert(lnum < len);
}
short lnum;
unsigned char data[200];
};
static vector<short> order;
static vector<unique_ptr<Graphic>> graphics;
static vector<size_t> indexes;
static void init()
{
order.reserve(len);
for (short i = 0; i < len; i++)
order.push_back(i);
graphics.reserve(nGraphics);
for (size_t i = 0; i < nGraphics; i++)
graphics.emplace_back(new Graphic);
assert(nGraphics >= nIndexes);
indexes.reserve(nIndexes);
for (size_t i = 0; i < nIndexes; i++)
indexes.push_back(i);
}
static bool is_selected(short lnum)
{
// worst case scenario (everything has been selected)
return true;
}
static bool is_valid(Graphic* g)
{
// worst case scenario (everything is valid)
return (g != nullptr);
}
static void benchmarks()
{
unordered_map<short, vector<Graphic*>> selected;
selected.reserve(len);
for (size_t i = 0; i < len; i++)
{
const auto lnum = order[i];
if (!is_selected(lnum))
continue;
selected.emplace(lnum, vector<Graphic*>());
}
for (const auto idx : indexes)
{
assert(idx < graphics.size());
const auto g = graphics[idx].get();
if (!is_valid(g))
continue;
const auto it = selected.find(g->lnum);
if (it != selected.end())
it->second.emplace_back(g);
}
for (size_t i = 0; i < len; i++)
{
const auto lnum = order[i];
if (!is_selected(lnum))
continue;
assert(selected.find(lnum) != selected.end());
for (const auto g : selected[lnum])
{
assert(g);
if (g->lnum != lnum)
throw runtime_error("error");
// perform slow operation on g (third party library)...
// must follow a specific order
}
// simulate operations
this_thread::sleep_for(microseconds{ selected[lnum].size() });
}
}
int main()
{
init();
const auto t0 = high_resolution_clock::now();
benchmarks();
const auto t1 = high_resolution_clock::now();
const auto elapsed = duration_cast<milliseconds>(t1 - t0).count();
cout << "Elapsed: " << elapsed << endl;
cin.get();
return 0;
}
Most of the work is done inside the third party library (the elapsed time well represents the actual application), but my code, used to prepare the data structure, last more than 50ms on my machine.
Is there any way to reduce this time?
Graphic
objects you could be faster by just pushing all selected objects into a single vector, sort this one by the order and then just iterate the vector. \$\endgroup\$graphics
? Why not make it avector<Graphic>
? \$\endgroup\$Graphic
is an "abstract" class.vector<Graphic*>
contains lines, polylines, rectangles, etc... \$\endgroup\$