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
TRACE_enable(char const * filename)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
TRACE_finish(void)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
TRACE_log(char const * method,PTime duration,ZSTD_Trace const * trace)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
ZSTD_trace_compress_begin(ZSTD_CCtx const * cctx)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
ZSTD_trace_compress_end(ZSTD_TraceCtx ctx,ZSTD_Trace const * trace)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
ZSTD_trace_decompress_begin(ZSTD_DCtx const * dctx)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
ZSTD_trace_decompress_end(ZSTD_TraceCtx ctx,ZSTD_Trace const * trace)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
TRACE_enable(char const * filename)165 void TRACE_enable(char const* filename)
166 {
167 (void)filename;
168 }
169
TRACE_finish(void)170 void TRACE_finish(void) {}
171
172 #endif /* ZSTD_TRACE */
173