Skip to content

Instantly share code, notes, and snippets.

@garettbass
Created August 11, 2019 18:15
Show Gist options
  • Save garettbass/e6334d5e7d4259990e1afd6eb11fabf8 to your computer and use it in GitHub Desktop.
Save garettbass/e6334d5e7d4259990e1afd6eb11fabf8 to your computer and use it in GitHub Desktop.
stlcost.cpp
/*
c++ --version; c++ -std=c++14 -g stlcost.cpp && ./a.out && rm ./a.out
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
iteration 0 -----------------------------------------
malloc():
InitImage: 6.111393 ms
MakeMips: 5.444773 ms
std::array:
InitImage: 5.191247 ms (0.85x)
MakeMips: 21.877937 ms (4x)
std::vector:
InitImage: 31.074629 ms (5.1x)
MakeMips: 22.224956 ms (4.1x)
iteration 1 -----------------------------------------
malloc():
InitImage: 16.152593 ms (2.6x)
MakeMips: 15.258340 ms (2.8x)
std::array:
InitImage: 6.697883 ms (1.1x)
MakeMips: 29.992644 ms (5.5x)
std::vector:
InitImage: 61.089039 ms (10x)
MakeMips: 34.484021 ms (6.3x)
iteration 2 -----------------------------------------
malloc():
InitImage: 2.333101 ms (0.38x)
MakeMips: 5.921506 ms (1.1x)
std::array:
InitImage: 16.481657 ms (2.7x)
MakeMips: 20.485178 ms (3.8x)
std::vector:
InitImage: 27.512777 ms (4.5x)
MakeMips: 18.223748 ms (3.3x)
*/
///usr/bin/env \
[ -n "${PATHEXT}" ] && ext='.exe'; \
bin="$(dirname $0)/$(basename ${0%.*})$ext"; \
c++ -std=c++14 -g -Werror -o $bin $0 \
&& $bin "$@"; \
status=$?; \
rm $bin; \
exit $status
// the size of the image that is made into mips
#define IMAGE_SIZE() 512
typedef float ChannelType;
#include <stdio.h>
#include <array>
#include <vector>
#include <chrono>
struct ScopedTimer
{
ScopedTimer(double& baseline, const char* label)
: m_baseline(baseline)
{
printf("%s: ", label);
m_start = std::chrono::high_resolution_clock::now();
}
~ScopedTimer()
{
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = std::chrono::duration_cast<std::chrono::duration<double>>(end - m_start);
const double elapsed = duration.count();
if (m_baseline == 0) {
printf("%f ms\n", elapsed * 1000.0);
m_baseline = elapsed;
} else {
printf("%f ms (%0.2gx)\n", elapsed * 1000.0, elapsed / m_baseline);
}
}
std::chrono::high_resolution_clock::time_point m_start;
double& m_baseline;
};
// calculate the total number of pixels needed to hold the image of size IMAGE_SIZE() as well as all the mips
constexpr size_t TotalPixelsMipped()
{
size_t ret = 0;
size_t size = IMAGE_SIZE();
while (size)
{
ret += size * size;
size /= 2;
}
return ret;
}
constexpr size_t TotalChannelsMipped()
{
// RGBA
return TotalPixelsMipped() * 4;
}
constexpr size_t NumMips()
{
size_t ret = 0;
size_t size = IMAGE_SIZE();
while (size)
{
ret++;
size /= 2;
}
return ret;
}
void GetMipInfo(size_t desiredMipIndex, size_t& offset, size_t& width)
{
offset = 0;
width = IMAGE_SIZE();
for (size_t mipIndex = 0; mipIndex < desiredMipIndex; ++mipIndex)
{
offset += width * width * 4;
width /= 2;
}
}
template<typename T>
void MakeMip(T& image, size_t mipIndex)
{
size_t srcOffset;
size_t srcWidth;
GetMipInfo(mipIndex - 1, srcOffset, srcWidth);
size_t destOffset;
size_t destWidth;
GetMipInfo(mipIndex, destOffset, destWidth);
for (size_t destY = 0; destY < destWidth; ++destY)
{
for (size_t destX = 0; destX < destWidth; ++destX)
{
for (size_t channel = 0; channel < 4; ++channel)
{
// 2x2 box filter source mip pixels
float value =
float(image[((destY * 2 + 0) * srcWidth + destX * 2 + 0) * 4 + srcOffset] + channel) +
float(image[((destY * 2 + 0) * srcWidth + destX * 2 + 1) * 4 + srcOffset] + channel) +
float(image[((destY * 2 + 1) * srcWidth + destX * 2 + 0) * 4 + srcOffset] + channel) +
float(image[((destY * 2 + 1) * srcWidth + destX * 2 + 1) * 4 + srcOffset] + channel);
image[destOffset] = ChannelType(value / 4.0f);
destOffset++;
}
}
}
}
template<typename T>
void MakeMips(T& image)
{
size_t mipCount = NumMips();
for (size_t mipIndex = 1; mipIndex < mipCount; ++mipIndex)
MakeMip(image, mipIndex);
}
template<typename T>
void InitImage(T& image)
{
memset(&image[0], 0, TotalChannelsMipped() * sizeof(ChannelType));
// It doesn't matter what we put into the image since we aren't ever looking at it, but initializing it anyhow.
size_t i = 0;
for (size_t y = 0; y < IMAGE_SIZE(); ++y)
{
for (size_t x = 0; x < IMAGE_SIZE(); ++x)
{
image[i * 4 + 0] = ChannelType(x % 256);
image[i * 4 + 1] = ChannelType(y % 256);
image[i * 4 + 2] = ChannelType(0);
image[i * 4 + 3] = ChannelType(255);
i++;
}
}
}
int main(void)
{
double init_image_baseline = 0, make_mips_baseline = 0;
for (int i = 0; i < 3; ++i){
printf("\niteration %i -----------------------------------------\n", i);
// c array
{
ChannelType* carray;
printf("\nmalloc():\n");
{
ScopedTimer timer(init_image_baseline, "InitImage");
carray = (ChannelType*)malloc(sizeof(ChannelType)*TotalChannelsMipped());
InitImage(carray);
}
{
ScopedTimer timer(make_mips_baseline, "MakeMips");
MakeMips(carray);
}
free(carray);
}
// std::array
// dynamically allocated to avoid a stack overflow
{
std::array<ChannelType, TotalChannelsMipped()>* array_ptr = new std::array<ChannelType, TotalChannelsMipped()>;
std::array<ChannelType, TotalChannelsMipped()>& array = *array_ptr;
printf("\nstd::array:\n");
{
ScopedTimer timer(init_image_baseline, "InitImage");
InitImage(array);
}
{
ScopedTimer timer(make_mips_baseline, "MakeMips");
MakeMips(array);
}
delete(array_ptr);
}
// std::vector
{
std::vector<ChannelType> vector;
printf("\nstd::vector:\n");
{
ScopedTimer timer(init_image_baseline, "InitImage");
vector.resize(TotalChannelsMipped());
InitImage(vector);
}
{
ScopedTimer timer(make_mips_baseline, "MakeMips");
MakeMips(vector);
}
}
}
#ifdef _MSC_VER
system("pause");
#endif
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment