Created
August 11, 2019 18:15
-
-
Save garettbass/e6334d5e7d4259990e1afd6eb11fabf8 to your computer and use it in GitHub Desktop.
stlcost.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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