profiledata_unittest.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
  2. // Copyright (c) 2007, Google Inc.
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. //
  31. // ---
  32. // Author: Chris Demetriou
  33. //
  34. // This file contains the unit tests for the ProfileData class.
  35. #if defined HAVE_STDINT_H
  36. #include <stdint.h> // to get uintptr_t
  37. #elif defined HAVE_INTTYPES_H
  38. #include <inttypes.h> // another place uintptr_t might be defined
  39. #endif
  40. #include <sys/stat.h>
  41. #include <sys/types.h>
  42. #include <fcntl.h>
  43. #include <string.h>
  44. #include <string>
  45. #include "profiledata.h"
  46. #include "base/commandlineflags.h"
  47. #include "base/logging.h"
  48. using std::string;
  49. // Some helpful macros for the test class
  50. #define TEST_F(cls, fn) void cls :: fn()
  51. namespace {
  52. template<typename T> class scoped_array {
  53. public:
  54. scoped_array(T* data) : data_(data) { }
  55. ~scoped_array() { delete[] data_; }
  56. T* get() { return data_; }
  57. T& operator[](int i) { return data_[i]; }
  58. private:
  59. T* const data_;
  60. };
  61. // Re-runs fn until it doesn't cause EINTR.
  62. #define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
  63. // Read up to "count" bytes from file descriptor "fd" into the buffer
  64. // starting at "buf" while handling short reads and EINTR. On
  65. // success, return the number of bytes read. Otherwise, return -1.
  66. static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
  67. CHECK_GE(fd, 0);
  68. char *buf0 = reinterpret_cast<char *>(buf);
  69. ssize_t num_bytes = 0;
  70. while (num_bytes < count) {
  71. ssize_t len;
  72. NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
  73. if (len < 0) { // There was an error other than EINTR.
  74. return -1;
  75. }
  76. if (len == 0) { // Reached EOF.
  77. break;
  78. }
  79. num_bytes += len;
  80. }
  81. CHECK(num_bytes <= count);
  82. return num_bytes;
  83. }
  84. // Thin wrapper around a file descriptor so that the file descriptor
  85. // gets closed for sure.
  86. struct FileDescriptor {
  87. const int fd_;
  88. explicit FileDescriptor(int fd) : fd_(fd) {}
  89. ~FileDescriptor() {
  90. if (fd_ >= 0) {
  91. NO_INTR(close(fd_));
  92. }
  93. }
  94. int get() { return fd_; }
  95. };
  96. // must be the same as with ProfileData::Slot.
  97. typedef uintptr_t ProfileDataSlot;
  98. // Quick and dirty function to make a number into a void* for use in a
  99. // sample.
  100. inline void* V(intptr_t x) { return reinterpret_cast<void*>(x); }
  101. // String returned by ProfileDataChecker helper functions to indicate success.
  102. const char kNoError[] = "";
  103. class ProfileDataChecker {
  104. public:
  105. ProfileDataChecker() {
  106. const char* tmpdir = getenv("TMPDIR");
  107. if (tmpdir == NULL)
  108. tmpdir = "/tmp";
  109. mkdir(tmpdir, 0755); // if necessary
  110. filename_ = string(tmpdir) + "/profiledata_unittest.tmp";
  111. }
  112. string filename() const { return filename_; }
  113. // Checks the first 'num_slots' profile data slots in the file
  114. // against the data pointed to by 'slots'. Returns kNoError if the
  115. // data matched, otherwise returns an indication of the cause of the
  116. // mismatch.
  117. string Check(const ProfileDataSlot* slots, int num_slots) {
  118. return CheckWithSkips(slots, num_slots, NULL, 0);
  119. }
  120. // Checks the first 'num_slots' profile data slots in the file
  121. // against the data pointed to by 'slots', skipping over entries
  122. // described by 'skips' and 'num_skips'.
  123. //
  124. // 'skips' must be a sorted list of (0-based) slot numbers to be
  125. // skipped, of length 'num_skips'. Note that 'num_slots' includes
  126. // any skipped slots, i.e., the first 'num_slots' profile data slots
  127. // will be considered, but some may be skipped.
  128. //
  129. // Returns kNoError if the data matched, otherwise returns an
  130. // indication of the cause of the mismatch.
  131. string CheckWithSkips(const ProfileDataSlot* slots, int num_slots,
  132. const int* skips, int num_skips);
  133. // Validate that a profile is correctly formed. The profile is
  134. // assumed to have been created by the same kind of binary (e.g.,
  135. // same slot size, same endian, etc.) as is validating the profile.
  136. //
  137. // Returns kNoError if the profile appears valid, otherwise returns
  138. // an indication of the problem with the profile.
  139. string ValidateProfile();
  140. private:
  141. string filename_;
  142. };
  143. string ProfileDataChecker::CheckWithSkips(const ProfileDataSlot* slots,
  144. int num_slots, const int* skips,
  145. int num_skips) {
  146. FileDescriptor fd(open(filename_.c_str(), O_RDONLY));
  147. if (fd.get() < 0)
  148. return "file open error";
  149. scoped_array<ProfileDataSlot> filedata(new ProfileDataSlot[num_slots]);
  150. size_t expected_bytes = num_slots * sizeof filedata[0];
  151. ssize_t bytes_read = ReadPersistent(fd.get(), filedata.get(), expected_bytes);
  152. if (expected_bytes != bytes_read)
  153. return "file too small";
  154. for (int i = 0; i < num_slots; i++) {
  155. if (num_skips > 0 && *skips == i) {
  156. num_skips--;
  157. skips++;
  158. continue;
  159. }
  160. if (slots[i] != filedata[i])
  161. return "data mismatch";
  162. }
  163. return kNoError;
  164. }
  165. string ProfileDataChecker::ValidateProfile() {
  166. FileDescriptor fd(open(filename_.c_str(), O_RDONLY));
  167. if (fd.get() < 0)
  168. return "file open error";
  169. struct stat statbuf;
  170. if (fstat(fd.get(), &statbuf) != 0)
  171. return "fstat error";
  172. if (statbuf.st_size != static_cast<ssize_t>(statbuf.st_size))
  173. return "file impossibly large";
  174. ssize_t filesize = statbuf.st_size;
  175. scoped_array<char> filedata(new char[filesize]);
  176. if (ReadPersistent(fd.get(), filedata.get(), filesize) != filesize)
  177. return "read of whole file failed";
  178. // Must have enough data for the header and the trailer.
  179. if (filesize < (5 + 3) * sizeof(ProfileDataSlot))
  180. return "not enough data in profile for header + trailer";
  181. // Check the header
  182. if (reinterpret_cast<ProfileDataSlot*>(filedata.get())[0] != 0)
  183. return "error in header: non-zero count";
  184. if (reinterpret_cast<ProfileDataSlot*>(filedata.get())[1] != 3)
  185. return "error in header: num_slots != 3";
  186. if (reinterpret_cast<ProfileDataSlot*>(filedata.get())[2] != 0)
  187. return "error in header: non-zero format version";
  188. // Period (slot 3) can have any value.
  189. if (reinterpret_cast<ProfileDataSlot*>(filedata.get())[4] != 0)
  190. return "error in header: non-zero padding value";
  191. ssize_t cur_offset = 5 * sizeof(ProfileDataSlot);
  192. // While there are samples, skip them. Each sample consists of
  193. // at least three slots.
  194. bool seen_trailer = false;
  195. while (!seen_trailer) {
  196. if (cur_offset > filesize - 3 * sizeof(ProfileDataSlot))
  197. return "truncated sample header";
  198. ProfileDataSlot* sample =
  199. reinterpret_cast<ProfileDataSlot*>(filedata.get() + cur_offset);
  200. ProfileDataSlot slots_this_sample = 2 + sample[1];
  201. ssize_t size_this_sample = slots_this_sample * sizeof(ProfileDataSlot);
  202. if (cur_offset > filesize - size_this_sample)
  203. return "truncated sample";
  204. if (sample[0] == 0 && sample[1] == 1 && sample[2] == 0) {
  205. seen_trailer = true;
  206. } else {
  207. if (sample[0] < 1)
  208. return "error in sample: sample count < 1";
  209. if (sample[1] < 1)
  210. return "error in sample: num_pcs < 1";
  211. for (int i = 2; i < slots_this_sample; i++) {
  212. if (sample[i] == 0)
  213. return "error in sample: NULL PC";
  214. }
  215. }
  216. cur_offset += size_this_sample;
  217. }
  218. // There must be at least one line in the (text) list of mapped objects,
  219. // and it must be terminated by a newline. Note, the use of newline
  220. // here and below Might not be reasonable on non-UNIX systems.
  221. if (cur_offset >= filesize)
  222. return "no list of mapped objects";
  223. if (filedata[filesize - 1] != '\n')
  224. return "profile did not end with a complete line";
  225. while (cur_offset < filesize) {
  226. char* line_start = filedata.get() + cur_offset;
  227. // Find the end of the line, and replace it with a NUL for easier
  228. // scanning.
  229. char* line_end = strchr(line_start, '\n');
  230. *line_end = '\0';
  231. // Advance past any leading space. It's allowed in some lines,
  232. // but not in others.
  233. bool has_leading_space = false;
  234. char* line_cur = line_start;
  235. while (*line_cur == ' ') {
  236. has_leading_space = true;
  237. line_cur++;
  238. }
  239. bool found_match = false;
  240. // Check for build lines.
  241. if (!found_match) {
  242. found_match = (strncmp(line_cur, "build=", 6) == 0);
  243. // Anything may follow "build=", and leading space is allowed.
  244. }
  245. // A line from ProcMapsIterator::FormatLine, of the form:
  246. //
  247. // 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so
  248. //
  249. // Leading space is not allowed. The filename may be omitted or
  250. // may consist of multiple words, so we scan only up to the
  251. // space before the filename.
  252. if (!found_match) {
  253. int chars_scanned = -1;
  254. sscanf(line_cur, "%*x-%*x %*c%*c%*c%*c %*x %*x:%*x %*d %n",
  255. &chars_scanned);
  256. found_match = (chars_scanned > 0 && !has_leading_space);
  257. }
  258. // A line from DumpAddressMap, of the form:
  259. //
  260. // 40000000-40015000: /lib/ld-2.3.2.so
  261. //
  262. // Leading space is allowed. The filename may be omitted or may
  263. // consist of multiple words, so we scan only up to the space
  264. // before the filename.
  265. if (!found_match) {
  266. int chars_scanned = -1;
  267. sscanf(line_cur, "%*x-%*x: %n", &chars_scanned);
  268. found_match = (chars_scanned > 0);
  269. }
  270. if (!found_match)
  271. return "unrecognized line in text section";
  272. cur_offset += (line_end - line_start) + 1;
  273. }
  274. return kNoError;
  275. }
  276. class ProfileDataTest {
  277. protected:
  278. void ExpectStopped() {
  279. EXPECT_FALSE(collector_.enabled());
  280. }
  281. void ExpectRunningSamples(int samples) {
  282. ProfileData::State state;
  283. collector_.GetCurrentState(&state);
  284. EXPECT_TRUE(state.enabled);
  285. EXPECT_EQ(samples, state.samples_gathered);
  286. }
  287. void ExpectSameState(const ProfileData::State& before,
  288. const ProfileData::State& after) {
  289. EXPECT_EQ(before.enabled, after.enabled);
  290. EXPECT_EQ(before.samples_gathered, after.samples_gathered);
  291. EXPECT_EQ(before.start_time, after.start_time);
  292. EXPECT_STREQ(before.profile_name, after.profile_name);
  293. }
  294. ProfileData collector_;
  295. ProfileDataChecker checker_;
  296. private:
  297. // The tests to run
  298. void OpsWhenStopped();
  299. void StartStopEmpty();
  300. void StartStopNoOptionsEmpty();
  301. void StartWhenStarted();
  302. void StartStopEmpty2();
  303. void CollectOne();
  304. void CollectTwoMatching();
  305. void CollectTwoFlush();
  306. void StartResetRestart();
  307. public:
  308. #define RUN(test) do { \
  309. printf("Running %s\n", #test); \
  310. ProfileDataTest pdt; \
  311. pdt.test(); \
  312. } while (0)
  313. static int RUN_ALL_TESTS() {
  314. RUN(OpsWhenStopped);
  315. RUN(StartStopEmpty);
  316. RUN(StartWhenStarted);
  317. RUN(StartStopEmpty2);
  318. RUN(CollectOne);
  319. RUN(CollectTwoMatching);
  320. RUN(CollectTwoFlush);
  321. RUN(StartResetRestart);
  322. return 0;
  323. }
  324. };
  325. // Check that various operations are safe when stopped.
  326. TEST_F(ProfileDataTest, OpsWhenStopped) {
  327. ExpectStopped();
  328. EXPECT_FALSE(collector_.enabled());
  329. // Verify that state is disabled, all-empty/all-0
  330. ProfileData::State state_before;
  331. collector_.GetCurrentState(&state_before);
  332. EXPECT_FALSE(state_before.enabled);
  333. EXPECT_EQ(0, state_before.samples_gathered);
  334. EXPECT_EQ(0, state_before.start_time);
  335. EXPECT_STREQ("", state_before.profile_name);
  336. // Safe to call stop again.
  337. collector_.Stop();
  338. // Safe to call FlushTable.
  339. collector_.FlushTable();
  340. // Safe to call Add.
  341. const void *trace[] = { V(100), V(101), V(102), V(103), V(104) };
  342. collector_.Add(arraysize(trace), trace);
  343. ProfileData::State state_after;
  344. collector_.GetCurrentState(&state_after);
  345. ExpectSameState(state_before, state_after);
  346. }
  347. // Start and Stop, collecting no samples. Verify output contents.
  348. TEST_F(ProfileDataTest, StartStopEmpty) {
  349. const int frequency = 1;
  350. ProfileDataSlot slots[] = {
  351. 0, 3, 0, 1000000 / frequency, 0, // binary header
  352. 0, 1, 0 // binary trailer
  353. };
  354. ExpectStopped();
  355. ProfileData::Options options;
  356. options.set_frequency(frequency);
  357. EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  358. ExpectRunningSamples(0);
  359. collector_.Stop();
  360. ExpectStopped();
  361. EXPECT_EQ(kNoError, checker_.ValidateProfile());
  362. EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
  363. }
  364. // Start and Stop with no options, collecting no samples. Verify
  365. // output contents.
  366. TEST_F(ProfileDataTest, StartStopNoOptionsEmpty) {
  367. // We're not requesting a specific period, implementation can do
  368. // whatever it likes.
  369. ProfileDataSlot slots[] = {
  370. 0, 3, 0, 0 /* skipped */, 0, // binary header
  371. 0, 1, 0 // binary trailer
  372. };
  373. int slots_to_skip[] = { 3 };
  374. ExpectStopped();
  375. EXPECT_TRUE(collector_.Start(checker_.filename().c_str(),
  376. ProfileData::Options()));
  377. ExpectRunningSamples(0);
  378. collector_.Stop();
  379. ExpectStopped();
  380. EXPECT_EQ(kNoError, checker_.ValidateProfile());
  381. EXPECT_EQ(kNoError, checker_.CheckWithSkips(slots, arraysize(slots),
  382. slots_to_skip,
  383. arraysize(slots_to_skip)));
  384. }
  385. // Start after already started. Should return false and not impact
  386. // collected data or state.
  387. TEST_F(ProfileDataTest, StartWhenStarted) {
  388. const int frequency = 1;
  389. ProfileDataSlot slots[] = {
  390. 0, 3, 0, 1000000 / frequency, 0, // binary header
  391. 0, 1, 0 // binary trailer
  392. };
  393. ProfileData::Options options;
  394. options.set_frequency(frequency);
  395. EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  396. ProfileData::State state_before;
  397. collector_.GetCurrentState(&state_before);
  398. options.set_frequency(frequency * 2);
  399. CHECK(!collector_.Start("foobar", options));
  400. ProfileData::State state_after;
  401. collector_.GetCurrentState(&state_after);
  402. ExpectSameState(state_before, state_after);
  403. collector_.Stop();
  404. ExpectStopped();
  405. EXPECT_EQ(kNoError, checker_.ValidateProfile());
  406. EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
  407. }
  408. // Like StartStopEmpty, but uses a different file name and frequency.
  409. TEST_F(ProfileDataTest, StartStopEmpty2) {
  410. const int frequency = 2;
  411. ProfileDataSlot slots[] = {
  412. 0, 3, 0, 1000000 / frequency, 0, // binary header
  413. 0, 1, 0 // binary trailer
  414. };
  415. ExpectStopped();
  416. ProfileData::Options options;
  417. options.set_frequency(frequency);
  418. EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  419. ExpectRunningSamples(0);
  420. collector_.Stop();
  421. ExpectStopped();
  422. EXPECT_EQ(kNoError, checker_.ValidateProfile());
  423. EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
  424. }
  425. TEST_F(ProfileDataTest, CollectOne) {
  426. const int frequency = 2;
  427. ProfileDataSlot slots[] = {
  428. 0, 3, 0, 1000000 / frequency, 0, // binary header
  429. 1, 5, 100, 101, 102, 103, 104, // our sample
  430. 0, 1, 0 // binary trailer
  431. };
  432. ExpectStopped();
  433. ProfileData::Options options;
  434. options.set_frequency(frequency);
  435. EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  436. ExpectRunningSamples(0);
  437. const void *trace[] = { V(100), V(101), V(102), V(103), V(104) };
  438. collector_.Add(arraysize(trace), trace);
  439. ExpectRunningSamples(1);
  440. collector_.Stop();
  441. ExpectStopped();
  442. EXPECT_EQ(kNoError, checker_.ValidateProfile());
  443. EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
  444. }
  445. TEST_F(ProfileDataTest, CollectTwoMatching) {
  446. const int frequency = 2;
  447. ProfileDataSlot slots[] = {
  448. 0, 3, 0, 1000000 / frequency, 0, // binary header
  449. 2, 5, 100, 201, 302, 403, 504, // our two samples
  450. 0, 1, 0 // binary trailer
  451. };
  452. ExpectStopped();
  453. ProfileData::Options options;
  454. options.set_frequency(frequency);
  455. EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  456. ExpectRunningSamples(0);
  457. for (int i = 0; i < 2; ++i) {
  458. const void *trace[] = { V(100), V(201), V(302), V(403), V(504) };
  459. collector_.Add(arraysize(trace), trace);
  460. ExpectRunningSamples(i + 1);
  461. }
  462. collector_.Stop();
  463. ExpectStopped();
  464. EXPECT_EQ(kNoError, checker_.ValidateProfile());
  465. EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
  466. }
  467. TEST_F(ProfileDataTest, CollectTwoFlush) {
  468. const int frequency = 2;
  469. ProfileDataSlot slots[] = {
  470. 0, 3, 0, 1000000 / frequency, 0, // binary header
  471. 1, 5, 100, 201, 302, 403, 504, // first sample (flushed)
  472. 1, 5, 100, 201, 302, 403, 504, // second identical sample
  473. 0, 1, 0 // binary trailer
  474. };
  475. ExpectStopped();
  476. ProfileData::Options options;
  477. options.set_frequency(frequency);
  478. EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  479. ExpectRunningSamples(0);
  480. const void *trace[] = { V(100), V(201), V(302), V(403), V(504) };
  481. collector_.Add(arraysize(trace), trace);
  482. ExpectRunningSamples(1);
  483. collector_.FlushTable();
  484. collector_.Add(arraysize(trace), trace);
  485. ExpectRunningSamples(2);
  486. collector_.Stop();
  487. ExpectStopped();
  488. EXPECT_EQ(kNoError, checker_.ValidateProfile());
  489. EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
  490. }
  491. // Start then reset, verify that the result is *not* a valid profile.
  492. // Then start again and make sure the result is OK.
  493. TEST_F(ProfileDataTest, StartResetRestart) {
  494. ExpectStopped();
  495. ProfileData::Options options;
  496. options.set_frequency(1);
  497. EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  498. ExpectRunningSamples(0);
  499. collector_.Reset();
  500. ExpectStopped();
  501. // We expect the resulting file to be empty. This is a minimal test
  502. // of ValidateProfile.
  503. EXPECT_NE(kNoError, checker_.ValidateProfile());
  504. struct stat statbuf;
  505. EXPECT_EQ(0, stat(checker_.filename().c_str(), &statbuf));
  506. EXPECT_EQ(0, statbuf.st_size);
  507. const int frequency = 2; // Different frequency than used above.
  508. ProfileDataSlot slots[] = {
  509. 0, 3, 0, 1000000 / frequency, 0, // binary header
  510. 0, 1, 0 // binary trailer
  511. };
  512. options.set_frequency(frequency);
  513. EXPECT_TRUE(collector_.Start(checker_.filename().c_str(), options));
  514. ExpectRunningSamples(0);
  515. collector_.Stop();
  516. ExpectStopped();
  517. EXPECT_EQ(kNoError, checker_.ValidateProfile());
  518. EXPECT_EQ(kNoError, checker_.Check(slots, arraysize(slots)));
  519. }
  520. } // namespace
  521. int main(int argc, char** argv) {
  522. int rc = ProfileDataTest::RUN_ALL_TESTS();
  523. printf("%s\n", rc == 0 ? "PASS" : "FAIL");
  524. return rc;
  525. }