1*3117ece4Schristos /* 2*3117ece4Schristos * Copyright (c) Meta Platforms, Inc. and affiliates. 3*3117ece4Schristos * All rights reserved. 4*3117ece4Schristos * 5*3117ece4Schristos * This source code is licensed under both the BSD-style license (found in the 6*3117ece4Schristos * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*3117ece4Schristos * in the COPYING file in the root directory of this source tree). 8*3117ece4Schristos * You may select, at your option, one of the above-listed licenses. 9*3117ece4Schristos */ 10*3117ece4Schristos 11*3117ece4Schristos #include "zstdcli_trace.h" 12*3117ece4Schristos 13*3117ece4Schristos #include <stdio.h> 14*3117ece4Schristos #include <stdlib.h> 15*3117ece4Schristos 16*3117ece4Schristos #include "timefn.h" 17*3117ece4Schristos #include "util.h" 18*3117ece4Schristos 19*3117ece4Schristos #define ZSTD_STATIC_LINKING_ONLY 20*3117ece4Schristos #include "../lib/zstd.h" 21*3117ece4Schristos /* We depend on the trace header to avoid duplicating the ZSTD_trace struct. 22*3117ece4Schristos * But, we check the version so it is compatible with dynamic linking. 23*3117ece4Schristos */ 24*3117ece4Schristos #include "../lib/common/zstd_trace.h" 25*3117ece4Schristos /* We only use macros from threading.h so it is compatible with dynamic linking */ 26*3117ece4Schristos #include "../lib/common/threading.h" 27*3117ece4Schristos 28*3117ece4Schristos #if ZSTD_TRACE 29*3117ece4Schristos 30*3117ece4Schristos static FILE* g_traceFile = NULL; 31*3117ece4Schristos static int g_mutexInit = 0; 32*3117ece4Schristos static ZSTD_pthread_mutex_t g_mutex; 33*3117ece4Schristos static UTIL_time_t g_enableTime = UTIL_TIME_INITIALIZER; 34*3117ece4Schristos 35*3117ece4Schristos void TRACE_enable(char const* filename) 36*3117ece4Schristos { 37*3117ece4Schristos int const writeHeader = !UTIL_isRegularFile(filename); 38*3117ece4Schristos if (g_traceFile) 39*3117ece4Schristos fclose(g_traceFile); 40*3117ece4Schristos g_traceFile = fopen(filename, "a"); 41*3117ece4Schristos if (g_traceFile && writeHeader) { 42*3117ece4Schristos /* Fields: 43*3117ece4Schristos * algorithm 44*3117ece4Schristos * version 45*3117ece4Schristos * method 46*3117ece4Schristos * streaming 47*3117ece4Schristos * level 48*3117ece4Schristos * workers 49*3117ece4Schristos * dictionary size 50*3117ece4Schristos * uncompressed size 51*3117ece4Schristos * compressed size 52*3117ece4Schristos * duration nanos 53*3117ece4Schristos * compression ratio 54*3117ece4Schristos * speed MB/s 55*3117ece4Schristos */ 56*3117ece4Schristos fprintf(g_traceFile, "Algorithm, Version, Method, Mode, Level, Workers, Dictionary Size, Uncompressed Size, Compressed Size, Duration Nanos, Compression Ratio, Speed MB/s\n"); 57*3117ece4Schristos } 58*3117ece4Schristos g_enableTime = UTIL_getTime(); 59*3117ece4Schristos if (!g_mutexInit) { 60*3117ece4Schristos if (!ZSTD_pthread_mutex_init(&g_mutex, NULL)) { 61*3117ece4Schristos g_mutexInit = 1; 62*3117ece4Schristos } else { 63*3117ece4Schristos TRACE_finish(); 64*3117ece4Schristos } 65*3117ece4Schristos } 66*3117ece4Schristos } 67*3117ece4Schristos 68*3117ece4Schristos void TRACE_finish(void) 69*3117ece4Schristos { 70*3117ece4Schristos if (g_traceFile) { 71*3117ece4Schristos fclose(g_traceFile); 72*3117ece4Schristos } 73*3117ece4Schristos g_traceFile = NULL; 74*3117ece4Schristos if (g_mutexInit) { 75*3117ece4Schristos ZSTD_pthread_mutex_destroy(&g_mutex); 76*3117ece4Schristos g_mutexInit = 0; 77*3117ece4Schristos } 78*3117ece4Schristos } 79*3117ece4Schristos 80*3117ece4Schristos static void TRACE_log(char const* method, PTime duration, ZSTD_Trace const* trace) 81*3117ece4Schristos { 82*3117ece4Schristos int level = 0; 83*3117ece4Schristos int workers = 0; 84*3117ece4Schristos double const ratio = (double)trace->uncompressedSize / (double)trace->compressedSize; 85*3117ece4Schristos double const speed = ((double)trace->uncompressedSize * 1000) / (double)duration; 86*3117ece4Schristos if (trace->params) { 87*3117ece4Schristos ZSTD_CCtxParams_getParameter(trace->params, ZSTD_c_compressionLevel, &level); 88*3117ece4Schristos ZSTD_CCtxParams_getParameter(trace->params, ZSTD_c_nbWorkers, &workers); 89*3117ece4Schristos } 90*3117ece4Schristos assert(g_traceFile != NULL); 91*3117ece4Schristos 92*3117ece4Schristos ZSTD_pthread_mutex_lock(&g_mutex); 93*3117ece4Schristos /* Fields: 94*3117ece4Schristos * algorithm 95*3117ece4Schristos * version 96*3117ece4Schristos * method 97*3117ece4Schristos * streaming 98*3117ece4Schristos * level 99*3117ece4Schristos * workers 100*3117ece4Schristos * dictionary size 101*3117ece4Schristos * uncompressed size 102*3117ece4Schristos * compressed size 103*3117ece4Schristos * duration nanos 104*3117ece4Schristos * compression ratio 105*3117ece4Schristos * speed MB/s 106*3117ece4Schristos */ 107*3117ece4Schristos fprintf(g_traceFile, 108*3117ece4Schristos "zstd, %u, %s, %s, %d, %d, %llu, %llu, %llu, %llu, %.2f, %.2f\n", 109*3117ece4Schristos trace->version, 110*3117ece4Schristos method, 111*3117ece4Schristos trace->streaming ? "streaming" : "single-pass", 112*3117ece4Schristos level, 113*3117ece4Schristos workers, 114*3117ece4Schristos (unsigned long long)trace->dictionarySize, 115*3117ece4Schristos (unsigned long long)trace->uncompressedSize, 116*3117ece4Schristos (unsigned long long)trace->compressedSize, 117*3117ece4Schristos (unsigned long long)duration, 118*3117ece4Schristos ratio, 119*3117ece4Schristos speed); 120*3117ece4Schristos ZSTD_pthread_mutex_unlock(&g_mutex); 121*3117ece4Schristos } 122*3117ece4Schristos 123*3117ece4Schristos /** 124*3117ece4Schristos * These symbols override the weak symbols provided by the library. 125*3117ece4Schristos */ 126*3117ece4Schristos 127*3117ece4Schristos ZSTD_TraceCtx ZSTD_trace_compress_begin(ZSTD_CCtx const* cctx) 128*3117ece4Schristos { 129*3117ece4Schristos (void)cctx; 130*3117ece4Schristos if (g_traceFile == NULL) 131*3117ece4Schristos return 0; 132*3117ece4Schristos return (ZSTD_TraceCtx)UTIL_clockSpanNano(g_enableTime); 133*3117ece4Schristos } 134*3117ece4Schristos 135*3117ece4Schristos void ZSTD_trace_compress_end(ZSTD_TraceCtx ctx, ZSTD_Trace const* trace) 136*3117ece4Schristos { 137*3117ece4Schristos PTime const beginNanos = (PTime)ctx; 138*3117ece4Schristos PTime const endNanos = UTIL_clockSpanNano(g_enableTime); 139*3117ece4Schristos PTime const durationNanos = endNanos > beginNanos ? endNanos - beginNanos : 0; 140*3117ece4Schristos assert(g_traceFile != NULL); 141*3117ece4Schristos assert(trace->version == ZSTD_VERSION_NUMBER); /* CLI version must match. */ 142*3117ece4Schristos TRACE_log("compress", durationNanos, trace); 143*3117ece4Schristos } 144*3117ece4Schristos 145*3117ece4Schristos ZSTD_TraceCtx ZSTD_trace_decompress_begin(ZSTD_DCtx const* dctx) 146*3117ece4Schristos { 147*3117ece4Schristos (void)dctx; 148*3117ece4Schristos if (g_traceFile == NULL) 149*3117ece4Schristos return 0; 150*3117ece4Schristos return (ZSTD_TraceCtx)UTIL_clockSpanNano(g_enableTime); 151*3117ece4Schristos } 152*3117ece4Schristos 153*3117ece4Schristos void ZSTD_trace_decompress_end(ZSTD_TraceCtx ctx, ZSTD_Trace const* trace) 154*3117ece4Schristos { 155*3117ece4Schristos PTime const beginNanos = (PTime)ctx; 156*3117ece4Schristos PTime const endNanos = UTIL_clockSpanNano(g_enableTime); 157*3117ece4Schristos PTime const durationNanos = endNanos > beginNanos ? endNanos - beginNanos : 0; 158*3117ece4Schristos assert(g_traceFile != NULL); 159*3117ece4Schristos assert(trace->version == ZSTD_VERSION_NUMBER); /* CLI version must match. */ 160*3117ece4Schristos TRACE_log("decompress", durationNanos, trace); 161*3117ece4Schristos } 162*3117ece4Schristos 163*3117ece4Schristos #else /* ZSTD_TRACE */ 164*3117ece4Schristos 165*3117ece4Schristos void TRACE_enable(char const* filename) 166*3117ece4Schristos { 167*3117ece4Schristos (void)filename; 168*3117ece4Schristos } 169*3117ece4Schristos 170*3117ece4Schristos void TRACE_finish(void) {} 171*3117ece4Schristos 172*3117ece4Schristos #endif /* ZSTD_TRACE */ 173