// ###################################################################### static void env_free_list_init(struct free_list* p, env_size_t size_check) { ENV_ASSERT(p->node_list == 0); ENV_ASSERT(size_check >= sizeof(struct free_list_node)); p->num_allocations = 0; p->alloc_size = size_check; p->num_active = 0; }
/** If there are chunks available in the free list, one of those is returned; otherwise new memory is allocated with (*g_raw_alloc). */ static void* env_free_list_allocate(struct free_list* p, env_size_t bytes) { ENV_ASSERT(bytes == p->alloc_size); if (p->node_list == 0) { ++p->num_allocations; ++p->num_active; ENV_ASSERT(g_raw_alloc != 0); void* const result = (*g_raw_alloc)(bytes); ENV_ASSERT2(result != 0, "Memory allocation failed"); return result; } struct free_list_node* n = p->node_list; p->node_list = p->node_list->next; ++p->num_active; return (void*) n; }
// ###################################################################### void env_c_inplace_normalize(intg32* const dst, const env_size_t sz, const intg32 nmin, const intg32 nmax, intg32* const actualmin_p, intg32* const actualmax_p, const intg32 rangeThresh) { ENV_ASSERT(sz > 0); ENV_ASSERT(nmax >= nmin); intg32 mi, ma; env_c_get_min_max(dst, sz, &mi, &ma); const intg32 old_scale = ma - mi; if (old_scale == 0 || old_scale < rangeThresh) // input image is uniform { for (env_size_t i = 0; i < sz; ++i) dst[i] = 0; return; } const intg32 new_scale = nmax - nmin; if (new_scale == 0) // output range is uniform { for (env_size_t i = 0; i < sz; ++i) dst[i] = nmin; return; } intg32 actualmin, actualmax; if (old_scale == new_scale) { const intg32 add = nmin - mi; if (add != 0) for (env_size_t i = 0; i < sz; ++i) dst[i] += add; actualmin = nmin; actualmax = nmax; } #if defined(ENV_INTG64_TYPE) else { for (env_size_t i = 0; i < sz; ++i) dst[i] = nmin + ((((intg64)(dst[i] - mi)) * new_scale) / old_scale); actualmin = nmin; actualmax = nmin + ((((intg64)(old_scale)) * new_scale) / old_scale); } #else else if (old_scale > new_scale)
// ###################################################################### static void env_free_list_cleanup(struct free_list* p) { ENV_ASSERT(p->num_active == 0); while (p->node_list) { void* space = p->node_list; p->node_list = p->node_list->next; ENV_ASSERT(g_raw_dealloc != 0); (*g_raw_dealloc)(space); --p->num_allocations; } ENV_ASSERT(p->num_allocations == 0); ENV_ASSERT(p->node_list == 0); // now we are back to a pristine state, so forget our size: p->alloc_size = 0; }
static void env_ori_subjob_run(void* p) { struct env_ori_subjob_data* j = (struct env_ori_subjob_data*)(p); env_chan_steerable (j->channame, j->envp, j->imath, j->dims, j->hipass9, j->thetaidx, j->status_func, j->status_userdata, &j->chanOut); ENV_ASSERT(env_img_initialized(&j->chanOut)); }
// ###################################################################### void env_stdio_write_gray(const struct env_image* iimage, const char* outstem, const char* name, int c) { if (!env_img_initialized(iimage)) return; // if outstem is the empty string, then the user wanted us to // suppress output: if (outstem[0] == '\0') return; char fname[256]; snprintf(fname, sizeof(fname), "%s-%s%06d.pnm", outstem, name, c); FILE* const f = fopen(fname, "wb"); if (f == 0) lfatal("%s: couldn't open PNM file for writing (errno=%d, %s)", fname, errno, strerror(errno)); //REV: so they are P5 (binary, greyscale), dim * dim images, with max value 255. if (fprintf(f, "P5\n%d %d\n255\n", (int) iimage->dims.w, (int) iimage->dims.h) < 0) lfatal("%s: fprintf() failed (errno=%d, %s)", fname, errno, strerror(errno)); const intg32* const src = env_img_pixels(iimage); const env_size_t sz = env_img_size(iimage); byte* bimage = (byte*) env_allocate(sz * sizeof(byte)); for (env_size_t i = 0; i < sz; ++i) { // the caller is supposed to have already ensured that // the intg32 image has been downsampled to a [0,255] // range, so let's verify that: ENV_ASSERT(src[i] >= 0 && src[i] <= 255); bimage[i] = (byte) src[i]; } //REV: they aren't using any newlines! if (fwrite(bimage, 1, sz, f) != sz) { env_deallocate(bimage); lfatal("%s: fwrite() failed (errno=%d, %s)", fname, errno, strerror(errno)); } env_deallocate(bimage); if (fclose(f) != 0) lfatal("%s: fclose() failed (errno=%d, %s)", fname, errno, strerror(errno)); }
// ###################################################################### void env_c_get_min_max(const intg32* src, const env_size_t sz, intg32* xmini, intg32* xmaxi) { ENV_ASSERT(sz > 0); *xmini = *xmaxi = src[0]; for (env_size_t i = 0; i < sz; ++i) { if (src[i] < *xmini) *xmini = src[i]; else if (src[i] > *xmaxi) *xmaxi = src[i]; } }
// ###################################################################### void env_params_validate(const struct env_params* envp) { ENV_ASSERT(envp->maxnorm_type == ENV_VCXNORM_NONE || envp->maxnorm_type == ENV_VCXNORM_MAXNORM); ENV_ASSERT((envp->scale_bits+1) < (8*sizeof(intg32))); #ifdef ENV_WITH_DYNAMIC_CHANNELS ENV_ASSERT(envp->num_motion_directions <= 99); #endif ENV_ASSERT(envp->num_orientations <= 99); ENV_ASSERT(envp->cs_lev_max >= envp->cs_lev_min); ENV_ASSERT(envp->cs_del_max >= envp->cs_del_min); ENV_ASSERT(env_total_weight(envp) > 0); }
// ###################################################################### static void div2(const env_size_t numer, const env_size_t denom, const env_size_t ndigits, env_size_t* const whole, env_size_t* const fract) { *whole = numer / denom; *fract = 0; env_size_t rem = numer - (*whole * denom); for (env_size_t i = 0; i < ndigits; ++i) { rem *= 10; const env_size_t newwhole = rem / denom; ENV_ASSERT(newwhole < 10); rem = rem - (newwhole * denom); *fract *= 10; *fract += newwhole; } }
// ###################################################################### void env_c_lowpass_5_y_dec_y_fewbits_optim(const intg32* src, const env_size_t w, const env_size_t h, intg32* dst, const env_size_t h2) { ENV_ASSERT(h2 == h/2); // ########## vertical pass (even though we scan horiz for speedup) const env_size_t w2 = w + w, w3 = w2 + w; // speedup if (h == 2 || h == 3) ////////////////////////////////////////////////// { // topmost points ( [ (6^) 4 ] / 10 )^T for (env_size_t i = 0; i < w; ++i) { *dst++ = (src[0] * 3 + src[w] * 2) / 5; src++; } src -= w; // go back to top-left } else ///////////////////////////////// general case for height >= 4 { // topmost points ( [ (8^) 4 ] / 12 )^T for (env_size_t k = 0; k < w; ++k) { *dst++ = (src[ 0] * 2 + src[ w]) / 3; src++; } src -= w; // go back to top-left // second point skipped // rest of the column except last 2 points ( [ .^ 4 (8) 4 ] / 16 )T for (env_size_t i = 0; i < h-3; i += 2) { for (env_size_t k = 0; k < w; ++k) { *dst++ = (src[ w] + src[w3] + src[w2] * 2) >> 2; src++; } src += w; } } }
// ###################################################################### static void env_aligned_alloc_deallocate(struct aligned_alloc* p, void* user_addr) { const struct alloc_info* const info = ((struct alloc_info*) user_addr) - 1; p->nbytes_current -= info->alloc_nbytes; --p->nallocations_current; // deallocate memory from the given free_list, otherwise free it // globally if (info->source != 0) { env_free_list_deallocate(info->source, info->alloc_addr); } else { ENV_ASSERT(g_raw_dealloc != 0); (*g_raw_dealloc)(info->alloc_addr); } }
static void env_direction_job_run(void* p) { struct env_direction_job_data* j = (struct env_direction_job_data*)(p); const env_size_t firstlevel = j->envp->cs_lev_min; const env_size_t depth = env_max_pyr_depth(j->envp); // theta = (360.0 * i) / chan->num_directions; const env_size_t thetaidx = (j->dir * ENV_TRIG_TABSIZ) / j->chan->num_directions; ENV_ASSERT(thetaidx < ENV_TRIG_TABSIZ); // create an empty pyramid struct env_pyr shiftedCur; env_pyr_init(&shiftedCur, depth); // fill the empty pyramid with the shifted version for (env_size_t i = firstlevel; i < depth; ++i) { env_img_resize_dims(env_pyr_imgw(&shiftedCur, i), env_pyr_img(j->unshiftedCur, i)->dims); env_shift_image(env_pyr_img(j->unshiftedCur, i), j->imath->costab[thetaidx], -j->imath->sintab[thetaidx], ENV_TRIG_NBITS, env_pyr_imgw(&shiftedCur, i)); } env_chan_direction(j->channame, j->envp, j->imath, j->inputdims, &j->chan->unshifted_prev, j->unshiftedCur, &j->chan->shifted_prev[j->dir], &shiftedCur, j->status_func, j->status_userdata, &j->chanOut); env_pyr_swap(&j->chan->shifted_prev[j->dir], &shiftedCur); env_pyr_make_empty(&shiftedCur); }
// ###################################################################### void env_c_lowpass_5_x_dec_x_fewbits_optim(const intg32* src, const env_size_t w, const env_size_t h, intg32* dst, const env_size_t w2) { ENV_ASSERT(w2 == w/2); if (w == 2 || w == 3) ////////////////////////////////////////////////// for (env_size_t j = 0; j < h; ++j) { // leftmost point [ (6^) 4 ] / 10 *dst++ = (src[0] * 3 + src[1] * 2) / 5; src += w; // src back to same position as dst } else ////////////////////////////// general case for width() >= 4 // *** unfolded version (all particular cases treated) for // max speed. // notations: in () is the position of dest ptr, and ^ is src ptr // ########## horizontal pass for (env_size_t j = 0; j < h; ++j) { const intg32* src2 = src; // leftmost point [ (8^) 4 ] / 12 *dst++ = (src2[0] * 2 + src2[1]) / 3; // skip second point // rest of the line except last 2 points [ .^ 4 (8) 4 ] / 16 for (env_size_t i = 0; i < w-3; i += 2) { *dst++ = (src2[1] + src2[3] + src2[2] * 2) >> 2; src2 += 2; } src += w; } }
// ###################################################################### void env_c_lowpass_9_x_fewbits_optim(const intg32* src, const env_size_t w, const env_size_t h, intg32* dst) { ENV_ASSERT(w >= 9); // boundary conditions: truncated filter for (env_size_t j = 0; j < h; ++j) { // leftmost points *dst++ = // [ (72^) 56 28 8 ] (src[0] * 72 + src[1] * 56 + src[2] * 28 + src[3] * 8 ) / 164; *dst++ = // [ 56^ (72) 56 28 8 ] ((src[0] + src[2]) * 56 + src[1] * 72 + src[3] * 28 + src[4] * 8 ) / 220; *dst++ = // [ 28^ 56 (72) 56 28 8 ] ((src[0] + src[4]) * 28 + (src[1] + src[3]) * 56 + src[2] * 72 + src[5] * 8 ) / 248; // far from the borders for (env_size_t i = 0; i < w - 6; ++i) { *dst++ = // [ 8^ 28 56 (72) 56 28 8 ] ((src[0] + src[6]) * 8 + (src[1] + src[5]) * 28 + (src[2] + src[4]) * 56 + src[3] * 72 ) >> 8; ++src; } // rightmost points *dst++ = // [ 8^ 28 56 (72) 56 28 ] (src[0] * 8 + (src[1] + src[5]) * 28 + (src[2] + src[4]) * 56 + src[3] * 72 ) / 248; ++src; *dst++ = // [ 8^ 28 56 (72) 56 ] (src[0] * 8 + src[1] * 28 + (src[2] + src[4]) * 56 + src[3] * 72 ) / 220; ++src; *dst++ = // [ 8^ 28 56 (72) ] (src[0] * 8 + src[1] * 28 + src[2] * 56 + src[3] * 72 ) / 164; src += 4; // src back to same as dst (start of next line) } }
// ###################################################################### void env_mt_motion_channel_input_and_consume_pyr( struct env_motion_channel* chan, const char* tagName, const struct env_params* envp, const struct env_math* imath, const struct env_dims inputdims, struct env_pyr* unshiftedCur, env_chan_status_func* status_func, void* status_userdata, struct env_image* result) { env_img_make_empty(result); if (chan->num_directions != envp->num_motion_directions) { env_motion_channel_destroy(chan); env_motion_channel_init(chan, envp); } if (chan->num_directions == 0) return; char buf[17] = { 'r', 'e', 'i', 'c', 'h', 'a', 'r', 'd', 't', // 0--8 '(', '_', '_', // 9--11 '/', '_', '_', ')', '\0' // 12--16 }; ENV_ASSERT(chan->num_directions <= 99); buf[13] = '0' + (chan->num_directions / 10); buf[14] = '0' + (chan->num_directions % 10); struct env_job* jobs = env_allocate(chan->num_directions * sizeof(struct env_job)); ENV_ASSERT2(jobs != 0, "env_allocate failed"); struct env_direction_job_data* jobdata = env_allocate(chan->num_directions * sizeof(struct env_direction_job_data)); ENV_ASSERT2(jobdata != 0, "env_allocate failed"); // compute Reichardt motion detection into several directions for (env_size_t dir = 0; dir < chan->num_directions; ++dir) { buf[10] = '0' + ((dir+1) / 10); buf[11] = '0' + ((dir+1) % 10); jobdata[dir].chan = chan; jobdata[dir].dir = dir; jobdata[dir].envp = envp; jobdata[dir].imath = imath; jobdata[dir].inputdims = inputdims; jobdata[dir].unshiftedCur = unshiftedCur; jobdata[dir].status_func = status_func; jobdata[dir].status_userdata = status_userdata; env_img_init_empty(&jobdata[dir].chanOut); for (env_size_t c = 0; c < sizeof(buf); ++c) jobdata[dir].channame[c] = buf[c]; jobs[dir].callback = &env_direction_job_run; jobs[dir].userdata = &jobdata[dir]; } env_run_jobs(&jobs[0], chan->num_directions); for (env_size_t dir = 0; dir < chan->num_directions; ++dir) { struct env_image* chanOut = &jobdata[dir].chanOut; if (env_img_initialized(chanOut)) { if (!env_img_initialized(result)) { env_img_resize_dims(result, chanOut->dims); env_c_image_div_scalar (env_img_pixels(chanOut), env_img_size(chanOut), (intg32) chan->num_directions, env_img_pixelsw(result)); } else { ENV_ASSERT (env_dims_equal(chanOut->dims, result->dims)); env_c_image_div_scalar_accum (env_img_pixels(chanOut), env_img_size(chanOut), (intg32) chan->num_directions, env_img_pixelsw(result)); } } env_img_make_empty(chanOut); } if (env_img_initialized(result)) { env_max_normalize_inplace(result, INTMAXNORMMIN, INTMAXNORMMAX, envp->maxnorm_type, envp->range_thresh); if (status_func) (*status_func)(status_userdata, tagName, result); } env_pyr_swap(unshiftedCur, &chan->unshifted_prev); env_pyr_make_empty(unshiftedCur); env_deallocate(jobdata); env_deallocate(jobs); }
// ###################################################################### void env_mt_chan_orientation(const char* tagName, const struct env_params* envp, const struct env_math* imath, const struct env_image* img, env_chan_status_func* status_func, void* status_userdata, struct env_image* result) { env_img_make_empty(result); if (envp->num_orientations == 0) return; struct env_pyr hipass9; env_pyr_init(&hipass9, env_max_pyr_depth(envp)); env_pyr_build_hipass_9(img, envp->cs_lev_min, imath, &hipass9); char buf[17] = { 's', 't', 'e', 'e', 'r', 'a', 'b', 'l', 'e', // 0--8 '(', '_', '_', // 9--11 '/', '_', '_', ')', '\0' // 12--16 }; ENV_ASSERT(envp->num_orientations <= 99); buf[13] = '0' + (envp->num_orientations / 10); buf[14] = '0' + (envp->num_orientations % 10); struct env_job* jobs = env_allocate(envp->num_orientations * sizeof(struct env_job)); ENV_ASSERT2(jobs != 0, "env_allocate failed"); struct env_ori_subjob_data* jobdata = env_allocate(envp->num_orientations * sizeof(struct env_ori_subjob_data)); ENV_ASSERT2(jobdata != 0, "env_allocate failed"); for (env_size_t i = 0; i < envp->num_orientations; ++i) { // theta = (180.0 * i) / envp->num_orientations + // 90.0, where ENV_TRIG_TABSIZ is equivalent to 360.0 // or 2*pi const env_size_t thetaidx = (ENV_TRIG_TABSIZ * i) / (2 * envp->num_orientations) + (ENV_TRIG_TABSIZ / 4); ENV_ASSERT(thetaidx < ENV_TRIG_TABSIZ); buf[10] = '0' + ((i+1) / 10); buf[11] = '0' + ((i+1) % 10); jobdata[i].envp = envp; jobdata[i].imath = imath; jobdata[i].dims = img->dims; jobdata[i].hipass9 = &hipass9; jobdata[i].thetaidx = thetaidx; jobdata[i].status_func = status_func; jobdata[i].status_userdata = status_userdata; env_img_init_empty(&jobdata[i].chanOut); for (env_size_t c = 0; c < sizeof(buf); ++c) jobdata[i].channame[c] = buf[c]; jobs[i].callback = &env_ori_subjob_run; jobs[i].userdata = &jobdata[i]; } env_run_jobs(&jobs[0], envp->num_orientations); for (env_size_t i = 0; i < envp->num_orientations; ++i) { struct env_image* chanOut = &jobdata[i].chanOut; if (!env_img_initialized(result)) { env_img_resize_dims(result, chanOut->dims); env_c_image_div_scalar (env_img_pixels(chanOut), env_img_size(chanOut), (intg32) envp->num_orientations, env_img_pixelsw(result)); } else { ENV_ASSERT(env_dims_equal(chanOut->dims, result->dims)); env_c_image_div_scalar_accum (env_img_pixels(chanOut), env_img_size(chanOut), (intg32) envp->num_orientations, env_img_pixelsw(result)); } env_img_make_empty(chanOut); } env_pyr_make_empty(&hipass9); ENV_ASSERT(env_img_initialized(result)); env_max_normalize_inplace(result, INTMAXNORMMIN, INTMAXNORMMAX, envp->maxnorm_type, envp->range_thresh); if (status_func) (*status_func)(status_userdata, tagName, result); env_deallocate(jobdata); env_deallocate(jobs); }
// ###################################################################### static void* env_aligned_alloc_allocate(struct aligned_alloc* p, env_size_t user_nbytes) { struct alloc_info info = { 0, 0, 0, { 0 } }; info.source = 0; // We request extra space beyond what the user wants -- NALIGN // extra bytes allow us to return an address to the user that // is aligned to a NALIGN-byte boundary, and sizeof(struct // alloc_info) extra bytes allow us to stick some auxiliary // info just ahead of the address that we return to the // user. Note that for convenience we have set things up so // that sizeof(struct alloc_info)==NALIGN, so the number of // extra bytes that we need is just 2*NALIGN. info.alloc_nbytes = user_nbytes+2*NALIGN; info.alloc_addr = 0; for (env_size_t i = 0; i < ENV_NCACHE; ++i) { if (p->cache[i].alloc_size > 0) { // we found a filled slot, but if it doesn't // match our requested size then we just skip // over it: if (p->cache[i].alloc_size != info.alloc_nbytes) continue; } else { // we found an empty slot, so let's initialize // a new free list for our requested size: env_free_list_init(&p->cache[i], info.alloc_nbytes); } // now, one way or the other we know that the slot // matches our requested size, so go ahead and request // an allocation: info.source = &p->cache[i]; info.alloc_addr = env_free_list_allocate(&p->cache[i], info.alloc_nbytes); break; } if (info.alloc_addr == 0) { info.source = 0; ENV_ASSERT(g_raw_alloc != 0); info.alloc_addr = (*g_raw_alloc)(info.alloc_nbytes); ENV_ASSERT2(info.alloc_addr != 0, "Memory allocation failed"); } /* We will set things up like this: +- address = value of info.alloc_addr | | +- address = return value | | of this function v v +---------------+------------------------+------------------------+ | len==adjust | len==NALIGN | len==user_nbytes | | contents: | contents: | contents: | | unused | struct alloc_info | empty space for user | | alignment: | alignment: | alignment: | | unknown | NALIGN-byte boundary | NALIGN-byte boundary | +---------------+------------------------+------------------------+ */ void* const user_addr = ((char*) info.alloc_addr) + (2*NALIGN) - ((unsigned long) info.alloc_addr) % NALIGN; ((struct alloc_info*) user_addr)[-1] = info; p->nbytes_alltime += info.alloc_nbytes; ++p->nallocations_alltime; p->nbytes_current += info.alloc_nbytes; ++p->nallocations_current; return user_addr; }
// ###################################################################### struct env_rgb_pixel* env_stdio_parse_rgb(const char* fname, struct env_dims* outdims) { FILE* f = fopen(fname, "rb"); if (f == 0) lfatal("Couldn't open file '%s' for reading.", fname); int c = getc(f); if (c != 'P') lfatal("Missing magic number in pnm file '%s'" "(got '%c' [%d], expected '%c' [%d]).", fname, c, c, 'P', 'P'); int mode = -1; int ret = fscanf(f, "%d", &mode); if (ret > 0 && mode != 6) lfatal("Wrong pnm mode (got 'P%d', expected 'P6')", //REV: so they expect P6, i.e. binary rgb! mode); while (1) { const int c = getc(f); //REV: they're getting one char at a time...removing all spaces... if (!isspace(c)) { ungetc(c, f); break; } } // copy and concatenate optional comment line(s) starting with '#' // into comments string //REV: they're removing comments and such...we won't need to worry about this... while (1) { const int c = getc(f); if (c != '#') { ungetc(c, f); break; } else { while (getc(f) != '\n') { /* empty loop */ } } } int w = -1; int h = -1; int maxGrey = -1; ret = fscanf(f, "%d %d %d", &w, &h, &maxGrey); //REV: they get the dimensions... and the max grey value (wth?) ENV_ASSERT(ret > 0); ENV_ASSERT(w > 0); ENV_ASSERT(h > 0); ENV_ASSERT(maxGrey > 0); // read one more character of whitespace from the stream after maxGrey c = getc(f); if ( !isspace(c) ) lfatal("Missing whitespace after maxGrey in pbm file '%s'.", fname); struct env_rgb_pixel* result = (struct env_rgb_pixel*) //REV: note RGB pixel is byte[3]. env_allocate(w * h * sizeof(struct env_rgb_pixel)); if (fread((char*) result, 3, w*h, f) != ((env_size_t)(w*h))) lfatal("%s: fread() failed", fname); outdims->w = w; outdims->h = h; return result; }
// ###################################################################### void env_c_lowpass_9_y_fewbits_optim(const intg32* src, const env_size_t w, const env_size_t h, intg32* dst) { ENV_ASSERT(h >= 9); // index computation speedup: const env_size_t w2 = w + w, w3 = w2 + w, w4 = w3 + w, w5 = w4 + w, w6 = w5 + w; // *** vertical pass *** for (env_size_t i = 0; i < w; ++i) { *dst++ = (src[ 0] * 72 + src[ w] * 56 + src[w2] * 28 + src[w3] * 8 ) / 164; ++src; } src -= w; // back to top-left for (env_size_t i = 0; i < w; ++i) { *dst++ = ((src[ 0] + src[w2]) * 56 + src[ w] * 72 + src[w3] * 28 + src[w4] * 8 ) / 220; ++src; } src -= w; // back to top-left for (env_size_t i = 0; i < w; ++i) { *dst++ = ((src[ 0] + src[w4]) * 28 + (src[ w] + src[w3]) * 56 + src[w2] * 72 + src[w5] * 8 ) / 248; ++src; } src -= w; // back to top-left for (env_size_t j = 0; j < h - 6; j ++) for (env_size_t i = 0; i < w; ++i) { *dst++ = ((src[ 0] + src[w6]) * 8 + (src[ w] + src[w5]) * 28 + (src[w2] + src[w4]) * 56 + src[w3] * 72 ) >> 8; ++src; } for (env_size_t i = 0; i < w; ++i) { *dst++ = (src[ 0] * 8 + (src[ w] + src[w5]) * 28 + (src[w2] + src[w4]) * 56 + src[w3] * 72 ) / 248; ++src; } for (env_size_t i = 0; i < w; ++i) { *dst++ = (src[ 0] * 8 + src[ w] * 28 + (src[w2] + src[w4]) * 56 + src[w3] * 72 ) / 220; ++src; } for (env_size_t i = 0; i < w; ++i) { *dst++ = (src[ 0] * 8 + src[ w] * 28 + src[w2] * 56 + src[w3] * 72 ) / 164; ++src; } }
// ###################################################################### void env_stdio_print_alloc_stats(const struct env_alloc_stats* p, const env_size_t block_size) { env_size_t kiB_block_size_whole, kiB_block_size_fract; div2(block_size, 1024, 2, &kiB_block_size_whole, &kiB_block_size_fract); ENV_ASSERT(block_size > 0); env_size_t n_cache_blocks = 0; for (env_size_t i = 0; i < p->ncache_used; ++i) { const env_size_t nb = (p->cache[i].num_allocations * p->cache[i].alloc_size); n_cache_blocks += p->cache[i].num_allocations; env_size_t kiB_alloc_whole, kiB_alloc_fract; div2(nb, 1024, 2, &kiB_alloc_whole, &kiB_alloc_fract); env_size_t kiB_alloc_size_whole, kiB_alloc_size_fract; div2(p->cache[i].alloc_size, 1024, 4, &kiB_alloc_size_whole, &kiB_alloc_size_fract); env_size_t alloc_percent_whole, alloc_percent_fract; div2(nb*100, p->bytes_allocated, 2, &alloc_percent_whole, &alloc_percent_fract); env_size_t block_ratio_whole, block_ratio_fract; char symbol; if (p->cache[i].alloc_size - p->overhead >= block_size || p->cache[i].alloc_size - p->overhead <= 1) { div2(p->cache[i].alloc_size - p->overhead, block_size, 1, &block_ratio_whole, &block_ratio_fract); symbol = '*'; } else { div2(block_size, p->cache[i].alloc_size - p->overhead, 1, &block_ratio_whole, &block_ratio_fract); symbol = '/'; } fprintf(stderr, "memstats: cache[%02lu/%02lu]: " "%5lu.%02lukiB (%3lu.%02lu%%) " "in %4lu allocations " "(%2lu active) of %5lu.%04lukiB" " (%lu.%02lukiB %c %5lu.%01lu + %2luB)\n", i, ENV_NCACHE, kiB_alloc_whole, kiB_alloc_fract, alloc_percent_whole, alloc_percent_fract, p->cache[i].num_allocations, p->cache[i].num_active, kiB_alloc_size_whole, kiB_alloc_size_fract, kiB_block_size_whole, kiB_block_size_fract, (int) symbol, block_ratio_whole, block_ratio_fract, p->overhead); } env_size_t kiB_alloc_whole, kiB_alloc_fract; div2(p->bytes_allocated, 1024, 2, &kiB_alloc_whole, &kiB_alloc_fract); env_size_t n_blocks_whole, n_blocks_fract; div2(p->bytes_allocated, block_size, 1, &n_blocks_whole, &n_blocks_fract); fprintf(stderr, "memstats: =====[TOTAL]: " "%5lu.%02lukiB (100.00%%) " "in %4lu allocations " "(%2lu active) ================" " (%lu.%02lukiB * %5lu.%01lu )\n", kiB_alloc_whole, kiB_alloc_fract, n_cache_blocks, p->nallocations_current, kiB_block_size_whole, kiB_block_size_fract, n_blocks_whole, n_blocks_fract); fprintf(stderr, "memstats: %lu/%lu cache table entries in use\n", p->ncache_used, ENV_NCACHE); fprintf(stderr, "memstats: block alignment: %lu bytes\n", p->nalign); fprintf(stderr, "memstats: all-time: %llukiB in %lu requested allocations\n", p->nbytes_alltime/1024, p->nallocations_alltime); fprintf(stderr, "memstats: current: %lukiB in %lu active allocations\n", (unsigned long)(p->nbytes_current/1024), p->nallocations_current); }