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