]> git.cworth.org Git - apitrace/blob - thirdparty/snappy/snappy-test.cc
d3d9state: Upack D3DFMT_R5G6B5 too.
[apitrace] / thirdparty / snappy / snappy-test.cc
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google Inc. nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 // Various stubs for the unit tests for the open-source version of Snappy.
30
31 #include "snappy-test.h"
32
33 #ifdef HAVE_WINDOWS_H
34 #define WIN32_LEAN_AND_MEAN
35 #include <windows.h>
36 #endif
37
38 #include <algorithm>
39
40 DEFINE_bool(run_microbenchmarks, true,
41             "Run microbenchmarks before doing anything else.");
42
43 namespace snappy {
44
45 string ReadTestDataFile(const string& base) {
46   string contents;
47   const char* srcdir = getenv("srcdir");  // This is set by Automake.
48   if (srcdir) {
49     File::ReadFileToStringOrDie(
50         string(srcdir) + "/testdata/" + base, &contents);
51   } else {
52     File::ReadFileToStringOrDie("testdata/" + base, &contents);
53   }
54   return contents;
55 }
56
57 string StringPrintf(const char* format, ...) {
58   char buf[4096];
59   va_list ap;
60   va_start(ap, format);
61   vsnprintf(buf, sizeof(buf), format, ap);
62   va_end(ap);
63   return buf;
64 }
65
66 bool benchmark_running = false;
67 int64 benchmark_real_time_us = 0;
68 int64 benchmark_cpu_time_us = 0;
69 string *benchmark_label = NULL;
70 int64 benchmark_bytes_processed = 0;
71
72 void ResetBenchmarkTiming() {
73   benchmark_real_time_us = 0;
74   benchmark_cpu_time_us = 0;
75 }
76
77 #ifdef WIN32
78 LARGE_INTEGER benchmark_start_real;
79 FILETIME benchmark_start_cpu;
80 #else  // WIN32
81 struct timeval benchmark_start_real;
82 struct rusage benchmark_start_cpu;
83 #endif  // WIN32
84
85 void StartBenchmarkTiming() {
86 #ifdef WIN32
87   QueryPerformanceCounter(&benchmark_start_real);
88   FILETIME dummy;
89   CHECK(GetProcessTimes(
90       GetCurrentProcess(), &dummy, &dummy, &dummy, &benchmark_start_cpu));
91 #else
92   gettimeofday(&benchmark_start_real, NULL);
93   if (getrusage(RUSAGE_SELF, &benchmark_start_cpu) == -1) {
94     perror("getrusage(RUSAGE_SELF)");
95     exit(1);
96   }
97 #endif
98   benchmark_running = true;
99 }
100
101 void StopBenchmarkTiming() {
102   if (!benchmark_running) {
103     return;
104   }
105
106 #ifdef WIN32
107   LARGE_INTEGER benchmark_stop_real;
108   LARGE_INTEGER benchmark_frequency;
109   QueryPerformanceCounter(&benchmark_stop_real);
110   QueryPerformanceFrequency(&benchmark_frequency);
111
112   double elapsed_real = static_cast<double>(
113       benchmark_stop_real.QuadPart - benchmark_start_real.QuadPart) /
114       benchmark_frequency.QuadPart;
115   benchmark_real_time_us += elapsed_real * 1e6 + 0.5;
116
117   FILETIME benchmark_stop_cpu, dummy;
118   CHECK(GetProcessTimes(
119       GetCurrentProcess(), &dummy, &dummy, &dummy, &benchmark_stop_cpu));
120
121   ULARGE_INTEGER start_ulargeint;
122   start_ulargeint.LowPart = benchmark_start_cpu.dwLowDateTime;
123   start_ulargeint.HighPart = benchmark_start_cpu.dwHighDateTime;
124
125   ULARGE_INTEGER stop_ulargeint;
126   stop_ulargeint.LowPart = benchmark_stop_cpu.dwLowDateTime;
127   stop_ulargeint.HighPart = benchmark_stop_cpu.dwHighDateTime;
128
129   benchmark_cpu_time_us +=
130       (stop_ulargeint.QuadPart - start_ulargeint.QuadPart + 5) / 10;
131 #else  // WIN32
132   struct timeval benchmark_stop_real;
133   gettimeofday(&benchmark_stop_real, NULL);
134   benchmark_real_time_us +=
135       1000000 * (benchmark_stop_real.tv_sec - benchmark_start_real.tv_sec);
136   benchmark_real_time_us +=
137       (benchmark_stop_real.tv_usec - benchmark_start_real.tv_usec);
138
139   struct rusage benchmark_stop_cpu;
140   if (getrusage(RUSAGE_SELF, &benchmark_stop_cpu) == -1) {
141     perror("getrusage(RUSAGE_SELF)");
142     exit(1);
143   }
144   benchmark_cpu_time_us += 1000000 * (benchmark_stop_cpu.ru_utime.tv_sec -
145                                       benchmark_start_cpu.ru_utime.tv_sec);
146   benchmark_cpu_time_us += (benchmark_stop_cpu.ru_utime.tv_usec -
147                             benchmark_start_cpu.ru_utime.tv_usec);
148 #endif  // WIN32
149
150   benchmark_running = false;
151 }
152
153 void SetBenchmarkLabel(const string& str) {
154   if (benchmark_label) {
155     delete benchmark_label;
156   }
157   benchmark_label = new string(str);
158 }
159
160 void SetBenchmarkBytesProcessed(int64 bytes) {
161   benchmark_bytes_processed = bytes;
162 }
163
164 struct BenchmarkRun {
165   int64 real_time_us;
166   int64 cpu_time_us;
167 };
168
169 struct BenchmarkCompareCPUTime {
170   bool operator() (const BenchmarkRun& a, const BenchmarkRun& b) const {
171     return a.cpu_time_us < b.cpu_time_us;
172   }
173 };
174
175 void Benchmark::Run() {
176   for (int test_case_num = start_; test_case_num <= stop_; ++test_case_num) {
177     // Run a few iterations first to find out approximately how fast
178     // the benchmark is.
179     const int kCalibrateIterations = 100;
180     ResetBenchmarkTiming();
181     StartBenchmarkTiming();
182     (*function_)(kCalibrateIterations, test_case_num);
183     StopBenchmarkTiming();
184
185     // Let each test case run for about 200ms, but at least as many
186     // as we used to calibrate.
187     // Run five times and pick the median.
188     const int kNumRuns = 5;
189     const int kMedianPos = kNumRuns / 2;
190     int num_iterations = 0;
191     if (benchmark_real_time_us > 0) {
192       num_iterations = 200000 * kCalibrateIterations / benchmark_real_time_us;
193     }
194     num_iterations = max(num_iterations, kCalibrateIterations);
195     BenchmarkRun benchmark_runs[kNumRuns];
196
197     for (int run = 0; run < kNumRuns; ++run) {
198       ResetBenchmarkTiming();
199       StartBenchmarkTiming();
200       (*function_)(num_iterations, test_case_num);
201       StopBenchmarkTiming();
202
203       benchmark_runs[run].real_time_us = benchmark_real_time_us;
204       benchmark_runs[run].cpu_time_us = benchmark_cpu_time_us;
205     }
206
207     nth_element(benchmark_runs,
208                 benchmark_runs + kMedianPos,
209                 benchmark_runs + kNumRuns,
210                 BenchmarkCompareCPUTime());
211     int64 real_time_us = benchmark_runs[kMedianPos].real_time_us;
212     int64 cpu_time_us = benchmark_runs[kMedianPos].cpu_time_us;
213     int64 bytes_per_second = benchmark_bytes_processed * 1000000 / cpu_time_us;
214
215     string heading = StringPrintf("%s/%d", name_.c_str(), test_case_num);
216     string human_readable_speed;
217     if (bytes_per_second < 1024) {
218       human_readable_speed = StringPrintf("%dB/s", bytes_per_second);
219     } else if (bytes_per_second < 1024 * 1024) {
220       human_readable_speed = StringPrintf(
221           "%.1fkB/s", bytes_per_second / 1024.0f);
222     } else if (bytes_per_second < 1024 * 1024 * 1024) {
223       human_readable_speed = StringPrintf(
224           "%.1fMB/s", bytes_per_second / (1024.0f * 1024.0f));
225     } else {
226       human_readable_speed = StringPrintf(
227           "%.1fGB/s", bytes_per_second / (1024.0f * 1024.0f * 1024.0f));
228     }
229
230     fprintf(stderr,
231 #ifdef WIN32
232             "%-18s %10I64d %10I64d %10d %s  %s\n",
233 #else
234             "%-18s %10lld %10lld %10d %s  %s\n",
235 #endif
236             heading.c_str(),
237             static_cast<long long>(real_time_us * 1000 / num_iterations),
238             static_cast<long long>(cpu_time_us * 1000 / num_iterations),
239             num_iterations,
240             human_readable_speed.c_str(),
241             benchmark_label->c_str());
242   }
243 }
244
245 #ifdef HAVE_LIBZ
246
247 ZLib::ZLib()
248     : comp_init_(false),
249       uncomp_init_(false) {
250   Reinit();
251 }
252
253 ZLib::~ZLib() {
254   if (comp_init_)   { deflateEnd(&comp_stream_); }
255   if (uncomp_init_) { inflateEnd(&uncomp_stream_); }
256 }
257
258 void ZLib::Reinit() {
259   compression_level_ = Z_DEFAULT_COMPRESSION;
260   window_bits_ = MAX_WBITS;
261   mem_level_ =  8;  // DEF_MEM_LEVEL
262   if (comp_init_) {
263     deflateEnd(&comp_stream_);
264     comp_init_ = false;
265   }
266   if (uncomp_init_) {
267     inflateEnd(&uncomp_stream_);
268     uncomp_init_ = false;
269   }
270   first_chunk_ = true;
271 }
272
273 void ZLib::Reset() {
274   first_chunk_ = true;
275 }
276
277 // --------- COMPRESS MODE
278
279 // Initialization method to be called if we hit an error while
280 // compressing. On hitting an error, call this method before returning
281 // the error.
282 void ZLib::CompressErrorInit() {
283   deflateEnd(&comp_stream_);
284   comp_init_ = false;
285   Reset();
286 }
287
288 int ZLib::DeflateInit() {
289   return deflateInit2(&comp_stream_,
290                       compression_level_,
291                       Z_DEFLATED,
292                       window_bits_,
293                       mem_level_,
294                       Z_DEFAULT_STRATEGY);
295 }
296
297 int ZLib::CompressInit(Bytef *dest, uLongf *destLen,
298                        const Bytef *source, uLong *sourceLen) {
299   int err;
300
301   comp_stream_.next_in = (Bytef*)source;
302   comp_stream_.avail_in = (uInt)*sourceLen;
303   if ((uLong)comp_stream_.avail_in != *sourceLen) return Z_BUF_ERROR;
304   comp_stream_.next_out = dest;
305   comp_stream_.avail_out = (uInt)*destLen;
306   if ((uLong)comp_stream_.avail_out != *destLen) return Z_BUF_ERROR;
307
308   if ( !first_chunk_ )   // only need to set up stream the first time through
309     return Z_OK;
310
311   if (comp_init_) {      // we've already initted it
312     err = deflateReset(&comp_stream_);
313     if (err != Z_OK) {
314       LOG(WARNING) << "ERROR: Can't reset compress object; creating a new one";
315       deflateEnd(&comp_stream_);
316       comp_init_ = false;
317     }
318   }
319   if (!comp_init_) {     // first use
320     comp_stream_.zalloc = (alloc_func)0;
321     comp_stream_.zfree = (free_func)0;
322     comp_stream_.opaque = (voidpf)0;
323     err = DeflateInit();
324     if (err != Z_OK) return err;
325     comp_init_ = true;
326   }
327   return Z_OK;
328 }
329
330 // In a perfect world we'd always have the full buffer to compress
331 // when the time came, and we could just call Compress().  Alas, we
332 // want to do chunked compression on our webserver.  In this
333 // application, we compress the header, send it off, then compress the
334 // results, send them off, then compress the footer.  Thus we need to
335 // use the chunked compression features of zlib.
336 int ZLib::CompressAtMostOrAll(Bytef *dest, uLongf *destLen,
337                               const Bytef *source, uLong *sourceLen,
338                               int flush_mode) {   // Z_FULL_FLUSH or Z_FINISH
339   int err;
340
341   if ( (err=CompressInit(dest, destLen, source, sourceLen)) != Z_OK )
342     return err;
343
344   // This is used to figure out how many bytes we wrote *this chunk*
345   int compressed_size = comp_stream_.total_out;
346
347   // Some setup happens only for the first chunk we compress in a run
348   if ( first_chunk_ ) {
349     first_chunk_ = false;
350   }
351
352   // flush_mode is Z_FINISH for all mode, Z_SYNC_FLUSH for incremental
353   // compression.
354   err = deflate(&comp_stream_, flush_mode);
355
356   *sourceLen = comp_stream_.avail_in;
357
358   if ((err == Z_STREAM_END || err == Z_OK)
359       && comp_stream_.avail_in == 0
360       && comp_stream_.avail_out != 0 ) {
361     // we processed everything ok and the output buffer was large enough.
362     ;
363   } else if (err == Z_STREAM_END && comp_stream_.avail_in > 0) {
364     return Z_BUF_ERROR;                            // should never happen
365   } else if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) {
366     // an error happened
367     CompressErrorInit();
368     return err;
369   } else if (comp_stream_.avail_out == 0) {     // not enough space
370     err = Z_BUF_ERROR;
371   }
372
373   assert(err == Z_OK || err == Z_STREAM_END || err == Z_BUF_ERROR);
374   if (err == Z_STREAM_END)
375     err = Z_OK;
376
377   // update the crc and other metadata
378   compressed_size = comp_stream_.total_out - compressed_size;  // delta
379   *destLen = compressed_size;
380
381   return err;
382 }
383
384 int ZLib::CompressChunkOrAll(Bytef *dest, uLongf *destLen,
385                              const Bytef *source, uLong sourceLen,
386                              int flush_mode) {   // Z_FULL_FLUSH or Z_FINISH
387   const int ret =
388     CompressAtMostOrAll(dest, destLen, source, &sourceLen, flush_mode);
389   if (ret == Z_BUF_ERROR)
390     CompressErrorInit();
391   return ret;
392 }
393
394 // This routine only initializes the compression stream once.  Thereafter, it
395 // just does a deflateReset on the stream, which should be faster.
396 int ZLib::Compress(Bytef *dest, uLongf *destLen,
397                    const Bytef *source, uLong sourceLen) {
398   int err;
399   if ( (err=CompressChunkOrAll(dest, destLen, source, sourceLen,
400                                Z_FINISH)) != Z_OK )
401     return err;
402   Reset();         // reset for next call to Compress
403
404   return Z_OK;
405 }
406
407
408 // --------- UNCOMPRESS MODE
409
410 int ZLib::InflateInit() {
411   return inflateInit2(&uncomp_stream_, MAX_WBITS);
412 }
413
414 // Initialization method to be called if we hit an error while
415 // uncompressing. On hitting an error, call this method before
416 // returning the error.
417 void ZLib::UncompressErrorInit() {
418   inflateEnd(&uncomp_stream_);
419   uncomp_init_ = false;
420   Reset();
421 }
422
423 int ZLib::UncompressInit(Bytef *dest, uLongf *destLen,
424                          const Bytef *source, uLong *sourceLen) {
425   int err;
426
427   uncomp_stream_.next_in = (Bytef*)source;
428   uncomp_stream_.avail_in = (uInt)*sourceLen;
429   // Check for source > 64K on 16-bit machine:
430   if ((uLong)uncomp_stream_.avail_in != *sourceLen) return Z_BUF_ERROR;
431
432   uncomp_stream_.next_out = dest;
433   uncomp_stream_.avail_out = (uInt)*destLen;
434   if ((uLong)uncomp_stream_.avail_out != *destLen) return Z_BUF_ERROR;
435
436   if ( !first_chunk_ )   // only need to set up stream the first time through
437     return Z_OK;
438
439   if (uncomp_init_) {    // we've already initted it
440     err = inflateReset(&uncomp_stream_);
441     if (err != Z_OK) {
442       LOG(WARNING)
443         << "ERROR: Can't reset uncompress object; creating a new one";
444       UncompressErrorInit();
445     }
446   }
447   if (!uncomp_init_) {
448     uncomp_stream_.zalloc = (alloc_func)0;
449     uncomp_stream_.zfree = (free_func)0;
450     uncomp_stream_.opaque = (voidpf)0;
451     err = InflateInit();
452     if (err != Z_OK) return err;
453     uncomp_init_ = true;
454   }
455   return Z_OK;
456 }
457
458 // If you compressed your data a chunk at a time, with CompressChunk,
459 // you can uncompress it a chunk at a time with UncompressChunk.
460 // Only difference bewteen chunked and unchunked uncompression
461 // is the flush mode we use: Z_SYNC_FLUSH (chunked) or Z_FINISH (unchunked).
462 int ZLib::UncompressAtMostOrAll(Bytef *dest, uLongf *destLen,
463                                 const Bytef *source, uLong *sourceLen,
464                                 int flush_mode) {  // Z_SYNC_FLUSH or Z_FINISH
465   int err = Z_OK;
466
467   if ( (err=UncompressInit(dest, destLen, source, sourceLen)) != Z_OK ) {
468     LOG(WARNING) << "UncompressInit: Error: " << err << " SourceLen: "
469                  << *sourceLen;
470     return err;
471   }
472
473   // This is used to figure out how many output bytes we wrote *this chunk*:
474   const uLong old_total_out = uncomp_stream_.total_out;
475
476   // This is used to figure out how many input bytes we read *this chunk*:
477   const uLong old_total_in = uncomp_stream_.total_in;
478
479   // Some setup happens only for the first chunk we compress in a run
480   if ( first_chunk_ ) {
481     first_chunk_ = false;                          // so we don't do this again
482
483     // For the first chunk *only* (to avoid infinite troubles), we let
484     // there be no actual data to uncompress.  This sometimes triggers
485     // when the input is only the gzip header, say.
486     if ( *sourceLen == 0 ) {
487       *destLen = 0;
488       return Z_OK;
489     }
490   }
491
492   // We'll uncompress as much as we can.  If we end OK great, otherwise
493   // if we get an error that seems to be the gzip footer, we store the
494   // gzip footer and return OK, otherwise we return the error.
495
496   // flush_mode is Z_SYNC_FLUSH for chunked mode, Z_FINISH for all mode.
497   err = inflate(&uncomp_stream_, flush_mode);
498
499   // Figure out how many bytes of the input zlib slurped up:
500   const uLong bytes_read = uncomp_stream_.total_in - old_total_in;
501   CHECK_LE(source + bytes_read, source + *sourceLen);
502   *sourceLen = uncomp_stream_.avail_in;
503
504   if ((err == Z_STREAM_END || err == Z_OK)  // everything went ok
505              && uncomp_stream_.avail_in == 0) {    // and we read it all
506     ;
507   } else if (err == Z_STREAM_END && uncomp_stream_.avail_in > 0) {
508     LOG(WARNING)
509       << "UncompressChunkOrAll: Received some extra data, bytes total: "
510       << uncomp_stream_.avail_in << " bytes: "
511       << string(reinterpret_cast<const char *>(uncomp_stream_.next_in),
512                 min(int(uncomp_stream_.avail_in), 20));
513     UncompressErrorInit();
514     return Z_DATA_ERROR;       // what's the extra data for?
515   } else if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) {
516     // an error happened
517     LOG(WARNING) << "UncompressChunkOrAll: Error: " << err
518                  << " avail_out: " << uncomp_stream_.avail_out;
519     UncompressErrorInit();
520     return err;
521   } else if (uncomp_stream_.avail_out == 0) {
522     err = Z_BUF_ERROR;
523   }
524
525   assert(err == Z_OK || err == Z_BUF_ERROR || err == Z_STREAM_END);
526   if (err == Z_STREAM_END)
527     err = Z_OK;
528
529   *destLen = uncomp_stream_.total_out - old_total_out;  // size for this call
530
531   return err;
532 }
533
534 int ZLib::UncompressChunkOrAll(Bytef *dest, uLongf *destLen,
535                                const Bytef *source, uLong sourceLen,
536                                int flush_mode) {  // Z_SYNC_FLUSH or Z_FINISH
537   const int ret =
538     UncompressAtMostOrAll(dest, destLen, source, &sourceLen, flush_mode);
539   if (ret == Z_BUF_ERROR)
540     UncompressErrorInit();
541   return ret;
542 }
543
544 int ZLib::UncompressAtMost(Bytef *dest, uLongf *destLen,
545                           const Bytef *source, uLong *sourceLen) {
546   return UncompressAtMostOrAll(dest, destLen, source, sourceLen, Z_SYNC_FLUSH);
547 }
548
549 // We make sure we've uncompressed everything, that is, the current
550 // uncompress stream is at a compressed-buffer-EOF boundary.  In gzip
551 // mode, we also check the gzip footer to make sure we pass the gzip
552 // consistency checks.  We RETURN true iff both types of checks pass.
553 bool ZLib::UncompressChunkDone() {
554   assert(!first_chunk_ && uncomp_init_);
555   // Make sure we're at the end-of-compressed-data point.  This means
556   // if we call inflate with Z_FINISH we won't consume any input or
557   // write any output
558   Bytef dummyin, dummyout;
559   uLongf dummylen = 0;
560   if ( UncompressChunkOrAll(&dummyout, &dummylen, &dummyin, 0, Z_FINISH)
561        != Z_OK ) {
562     return false;
563   }
564
565   // Make sure that when we exit, we can start a new round of chunks later
566   Reset();
567
568   return true;
569 }
570
571 // Uncompresses the source buffer into the destination buffer.
572 // The destination buffer must be long enough to hold the entire
573 // decompressed contents.
574 //
575 // We only initialize the uncomp_stream once.  Thereafter, we use
576 // inflateReset, which should be faster.
577 //
578 // Returns Z_OK on success, otherwise, it returns a zlib error code.
579 int ZLib::Uncompress(Bytef *dest, uLongf *destLen,
580                      const Bytef *source, uLong sourceLen) {
581   int err;
582   if ( (err=UncompressChunkOrAll(dest, destLen, source, sourceLen,
583                                  Z_FINISH)) != Z_OK ) {
584     Reset();                           // let us try to compress again
585     return err;
586   }
587   if ( !UncompressChunkDone() )        // calls Reset()
588     return Z_DATA_ERROR;
589   return Z_OK;  // stream_end is ok
590 }
591
592 #endif  // HAVE_LIBZ
593
594 }  // namespace snappy