1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <gtest/gtest.h> 18 19 #include <android-base/file.h> 20 #include <android-base/stringprintf.h> 21 #include <android-base/strings.h> 22 23 #include <thread> 24 25 #include "cmd_stat_impl.h" 26 #include "command.h" 27 #include "environment.h" 28 #include "event_selection_set.h" 29 #include "get_test_data.h" 30 #include "test_util.h" 31 32 using namespace simpleperf; 33 34 static std::unique_ptr<Command> StatCmd() { 35 return CreateCommandInstance("stat"); 36 } 37 38 TEST(stat_cmd, no_options) { ASSERT_TRUE(StatCmd()->Run({"sleep", "1"})); } 39 40 TEST(stat_cmd, event_option) { 41 ASSERT_TRUE(StatCmd()->Run({"-e", "cpu-clock,task-clock", "sleep", "1"})); 42 } 43 44 TEST(stat_cmd, system_wide_option) { 45 TEST_IN_ROOT(ASSERT_TRUE(StatCmd()->Run({"-a", "sleep", "1"}))); 46 } 47 48 TEST(stat_cmd, verbose_option) { 49 ASSERT_TRUE(StatCmd()->Run({"--verbose", "sleep", "1"})); 50 } 51 52 TEST(stat_cmd, tracepoint_event) { 53 TEST_IN_ROOT(ASSERT_TRUE( 54 StatCmd()->Run({"-a", "-e", "sched:sched_switch", "sleep", "1"}))); 55 } 56 57 TEST(stat_cmd, rN_event) { 58 TEST_REQUIRE_HW_COUNTER(); 59 OMIT_TEST_ON_NON_NATIVE_ABIS(); 60 size_t event_number; 61 if (GetBuildArch() == ARCH_ARM64 || GetBuildArch() == ARCH_ARM) { 62 // As in D5.10.2 of the ARMv8 manual, ARM defines the event number space for PMU. part of the 63 // space is for common event numbers (which will stay the same for all ARM chips), part of the 64 // space is for implementation defined events. Here 0x08 is a common event for instructions. 65 event_number = 0x08; 66 } else if (GetBuildArch() == ARCH_X86_32 || GetBuildArch() == ARCH_X86_64) { 67 // As in volume 3 chapter 19 of the Intel manual, 0x00c0 is the event number for instruction. 68 event_number = 0x00c0; 69 } else { 70 GTEST_LOG_(INFO) << "Omit arch " << GetBuildArch(); 71 return; 72 } 73 std::string event_name = android::base::StringPrintf("r%zx", event_number); 74 ASSERT_TRUE(StatCmd()->Run({"-e", event_name, "sleep", "1"})); 75 } 76 77 TEST(stat_cmd, pmu_event) { 78 TEST_REQUIRE_PMU_COUNTER(); 79 TEST_REQUIRE_HW_COUNTER(); 80 std::string event_string; 81 if (GetBuildArch() == ARCH_X86_64) { 82 event_string = "cpu/instructions/"; 83 } else if (GetBuildArch() == ARCH_ARM64) { 84 event_string = "armv8_pmuv3/inst_retired/"; 85 } else { 86 GTEST_LOG_(INFO) << "Omit arch " << GetBuildArch(); 87 return; 88 } 89 TEST_IN_ROOT(ASSERT_TRUE( 90 StatCmd()->Run({"-a", "-e", event_string, "sleep", "1"}))); 91 } 92 93 TEST(stat_cmd, event_modifier) { 94 TEST_REQUIRE_HW_COUNTER(); 95 ASSERT_TRUE( 96 StatCmd()->Run({"-e", "cpu-cycles:u,cpu-cycles:k", "sleep", "1"})); 97 } 98 99 void RunWorkloadFunction() { 100 while (true) { 101 for (volatile int i = 0; i < 10000; ++i); 102 usleep(1); 103 } 104 } 105 106 void CreateProcesses(size_t count, 107 std::vector<std::unique_ptr<Workload>>* workloads) { 108 workloads->clear(); 109 // Create workloads run longer than profiling time. 110 for (size_t i = 0; i < count; ++i) { 111 std::unique_ptr<Workload> workload; 112 workload = Workload::CreateWorkload(RunWorkloadFunction); 113 ASSERT_TRUE(workload != nullptr); 114 ASSERT_TRUE(workload->Start()); 115 workloads->push_back(std::move(workload)); 116 } 117 } 118 119 TEST(stat_cmd, existing_processes) { 120 std::vector<std::unique_ptr<Workload>> workloads; 121 CreateProcesses(2, &workloads); 122 std::string pid_list = android::base::StringPrintf( 123 "%d,%d", workloads[0]->GetPid(), workloads[1]->GetPid()); 124 ASSERT_TRUE(StatCmd()->Run({"-p", pid_list, "sleep", "1"})); 125 } 126 127 TEST(stat_cmd, existing_threads) { 128 std::vector<std::unique_ptr<Workload>> workloads; 129 CreateProcesses(2, &workloads); 130 // Process id can be used as thread id in linux. 131 std::string tid_list = android::base::StringPrintf( 132 "%d,%d", workloads[0]->GetPid(), workloads[1]->GetPid()); 133 ASSERT_TRUE(StatCmd()->Run({"-t", tid_list, "sleep", "1"})); 134 } 135 136 TEST(stat_cmd, no_monitored_threads) { 137 ASSERT_FALSE(StatCmd()->Run({})); 138 ASSERT_FALSE(StatCmd()->Run({""})); 139 } 140 141 TEST(stat_cmd, group_option) { 142 TEST_REQUIRE_HW_COUNTER(); 143 ASSERT_TRUE( 144 StatCmd()->Run({"--group", "cpu-clock,page-faults", "sleep", "1"})); 145 ASSERT_TRUE(StatCmd()->Run({"--group", "cpu-cycles,instructions", "--group", 146 "cpu-cycles:u,instructions:u", "--group", 147 "cpu-cycles:k,instructions:k", "sleep", "1"})); 148 } 149 150 TEST(stat_cmd, auto_generated_summary) { 151 TEST_REQUIRE_HW_COUNTER(); 152 TemporaryFile tmp_file; 153 ASSERT_TRUE(StatCmd()->Run({"--group", "instructions:u,instructions:k", "-o", 154 tmp_file.path, "sleep", "1"})); 155 std::string s; 156 ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &s)); 157 size_t pos = s.find("instructions:u"); 158 ASSERT_NE(s.npos, pos); 159 pos = s.find("instructions:k", pos); 160 ASSERT_NE(s.npos, pos); 161 pos += strlen("instructions:k"); 162 // Check if the summary of instructions is generated. 163 ASSERT_NE(s.npos, s.find("instructions", pos)); 164 } 165 166 TEST(stat_cmd, duration_option) { 167 ASSERT_TRUE( 168 StatCmd()->Run({"--duration", "1.2", "-p", std::to_string(getpid()), "--in-app"})); 169 ASSERT_TRUE(StatCmd()->Run({"--duration", "1", "sleep", "2"})); 170 } 171 172 TEST(stat_cmd, interval_option) { 173 TemporaryFile tmp_file; 174 ASSERT_TRUE( 175 StatCmd()->Run({"--interval", "500.0", "--duration", "1.2", "-o", 176 tmp_file.path, "sleep", "2"})); 177 std::string s; 178 ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &s)); 179 size_t count = 0; 180 size_t pos = 0; 181 std::string subs = "statistics:"; 182 while((pos = s.find(subs, pos)) != s.npos) { 183 pos += subs.size(); 184 ++count ; 185 } 186 ASSERT_EQ(count, 2UL); 187 } 188 189 TEST(stat_cmd, interval_option_in_system_wide) { 190 TEST_IN_ROOT(ASSERT_TRUE(StatCmd()->Run({"-a", "--interval", "100", "--duration", "0.3"}))); 191 } 192 193 TEST(stat_cmd, interval_only_values_option) { 194 ASSERT_TRUE(StatCmd()->Run({"--interval", "500", "--interval-only-values", "sleep", "2"})); 195 TEST_IN_ROOT(ASSERT_TRUE(StatCmd()->Run({"-a", "--interval", "100", "--interval-only-values", 196 "--duration", "0.3"}))); 197 } 198 199 TEST(stat_cmd, no_modifier_for_clock_events) { 200 for (const std::string& e : {"cpu-clock", "task-clock"}) { 201 for (const std::string& m : {"u", "k"}) { 202 ASSERT_FALSE(StatCmd()->Run({"-e", e + ":" + m, "sleep", "0.1"})) 203 << "event " << e << ":" << m; 204 } 205 } 206 } 207 208 TEST(stat_cmd, handle_SIGHUP) { 209 std::thread thread([]() { 210 sleep(1); 211 kill(getpid(), SIGHUP); 212 }); 213 thread.detach(); 214 ASSERT_TRUE(StatCmd()->Run({"sleep", "1000000"})); 215 } 216 217 TEST(stat_cmd, stop_when_no_more_targets) { 218 std::atomic<int> tid(0); 219 std::thread thread([&]() { 220 tid = gettid(); 221 sleep(1); 222 }); 223 thread.detach(); 224 while (tid == 0); 225 ASSERT_TRUE(StatCmd()->Run({"-t", std::to_string(tid), "--in-app"})); 226 } 227 228 TEST(stat_cmd, sample_speed_should_be_zero) { 229 TEST_REQUIRE_HW_COUNTER(); 230 EventSelectionSet set(true); 231 ASSERT_TRUE(set.AddEventType("cpu-cycles")); 232 set.AddMonitoredProcesses({getpid()}); 233 ASSERT_TRUE(set.OpenEventFiles({-1})); 234 std::vector<EventAttrWithId> attrs = set.GetEventAttrWithId(); 235 ASSERT_GT(attrs.size(), 0u); 236 for (auto& attr : attrs) { 237 ASSERT_EQ(attr.attr->sample_period, 0u); 238 ASSERT_EQ(attr.attr->sample_freq, 0u); 239 ASSERT_EQ(attr.attr->freq, 0u); 240 } 241 } 242 243 TEST(stat_cmd, calculating_cpu_frequency) { 244 TEST_REQUIRE_HW_COUNTER(); 245 CaptureStdout capture; 246 ASSERT_TRUE(capture.Start()); 247 ASSERT_TRUE(StatCmd()->Run({"--csv", "--group", "task-clock,cpu-cycles", "sleep", "1"})); 248 std::string output = capture.Finish(); 249 double task_clock_in_ms = 0; 250 uint64_t cpu_cycle_count = 0; 251 double cpu_frequency = 0; 252 for (auto& line : android::base::Split(output, "\n")) { 253 if (line.find("task-clock") != std::string::npos) { 254 ASSERT_EQ(sscanf(line.c_str(), "%lf(ms)", &task_clock_in_ms), 1); 255 } else if (line.find("cpu-cycles") != std::string::npos) { 256 ASSERT_EQ(sscanf(line.c_str(), "%" SCNu64 ",cpu-cycles,%lf", &cpu_cycle_count, 257 &cpu_frequency), 2); 258 } 259 } 260 ASSERT_NE(task_clock_in_ms, 0.0f); 261 ASSERT_NE(cpu_cycle_count, 0u); 262 ASSERT_NE(cpu_frequency, 0.0f); 263 double calculated_frequency = cpu_cycle_count / task_clock_in_ms / 1e6; 264 // Accept error up to 1e-3. Because the stat cmd print values with precision 1e-6. 265 ASSERT_NEAR(cpu_frequency, calculated_frequency, 1e-3); 266 } 267 268 TEST(stat_cmd, set_comm_in_another_thread) { 269 // Test a kernel bug which was fixed in 3.15. If kernel panic happens, please cherry pick kernel 270 // patch: e041e328c4b41e perf: Fix perf_event_comm() vs. exec() assumption 271 TEST_REQUIRE_HW_COUNTER(); 272 273 for (size_t loop = 0; loop < 3; ++loop) { 274 std::atomic<int> child_tid(0); 275 std::atomic<bool> stop_child(false); 276 std::thread child([&]() { 277 child_tid = gettid(); 278 // stay on a cpu to make the monitored events of the child thread on that cpu. 279 while (!stop_child) {} 280 }); 281 282 while (child_tid == 0) {} 283 284 { 285 EventSelectionSet set(true); 286 ASSERT_TRUE(set.AddEventType("cpu-cycles")); 287 set.AddMonitoredThreads({child_tid}); 288 ASSERT_TRUE(set.OpenEventFiles({-1})); 289 290 EventSelectionSet set2(true); 291 ASSERT_TRUE(set2.AddEventType("instructions")); 292 set2.AddMonitoredThreads({gettid()}); 293 ASSERT_TRUE(set2.OpenEventFiles({-1})); 294 295 // For kernels with the bug, setting comm will make the monitored events of the child thread 296 // on the cpu of the current thread. 297 ASSERT_TRUE(android::base::WriteStringToFile("child", 298 "/proc/" + std::to_string(child_tid) + "/comm")); 299 // Release monitored events. For kernels with the bug, the events still exist on the cpu of 300 // the child thread. 301 } 302 303 stop_child = true; 304 child.join(); 305 // Sleep 1s to enter and exit cpu idle, which may abort the kernel. 306 sleep(1); 307 } 308 } 309 310 static void TestStatingApps(const std::string& app_name) { 311 // Bring the app to foreground. 312 ASSERT_TRUE(Workload::RunCmd({"am", "start", app_name + "/.MainActivity"})); 313 ASSERT_TRUE(StatCmd()->Run({"--app", app_name, "--duration", "3"})); 314 } 315 316 TEST(stat_cmd, app_option_for_debuggable_app) { 317 TEST_REQUIRE_APPS(); 318 SetRunInAppToolForTesting(true, false); 319 TestStatingApps("com.android.simpleperf.debuggable"); 320 SetRunInAppToolForTesting(false, true); 321 TestStatingApps("com.android.simpleperf.debuggable"); 322 } 323 324 TEST(stat_cmd, app_option_for_profileable_app) { 325 TEST_REQUIRE_APPS(); 326 SetRunInAppToolForTesting(false, true); 327 TestStatingApps("com.android.simpleperf.profileable"); 328 } 329 330 TEST(stat_cmd, use_devfreq_counters_option) { 331 #if defined(__ANDROID__) 332 TEST_IN_ROOT(StatCmd()->Run({"--use-devfreq-counters", "sleep", "0.1"})); 333 #else 334 GTEST_LOG_(INFO) << "This test tests an option only available on Android."; 335 #endif 336 } 337 338 TEST(stat_cmd, per_thread_option) { 339 ASSERT_TRUE(StatCmd()->Run({"--per-thread", "sleep", "0.1"})); 340 TEST_IN_ROOT(StatCmd()->Run({"--per-thread", "-a", "--duration", "0.1"})); 341 } 342 343 TEST(stat_cmd, per_core_option) { 344 ASSERT_TRUE(StatCmd()->Run({"--per-core", "sleep", "0.1"})); 345 TEST_IN_ROOT(StatCmd()->Run({"--per-core", "-a", "--duration", "0.1"})); 346 } 347 348 TEST(stat_cmd, counter_sum) { 349 PerfCounter counter; 350 counter.value = 1; 351 counter.time_enabled = 2; 352 counter.time_running = 3; 353 CounterSum a; 354 a.FromCounter(counter); 355 ASSERT_EQ(a.value, 1); 356 ASSERT_EQ(a.time_enabled, 2); 357 ASSERT_EQ(a.time_running, 3); 358 CounterSum b = a + a; 359 ASSERT_EQ(b.value, 2); 360 ASSERT_EQ(b.time_enabled, 4); 361 ASSERT_EQ(b.time_running, 6); 362 CounterSum c = a - a; 363 ASSERT_EQ(c.value, 0); 364 ASSERT_EQ(c.time_enabled, 0); 365 ASSERT_EQ(c.time_running, 0); 366 b.ToCounter(counter); 367 ASSERT_EQ(counter.value, 2); 368 ASSERT_EQ(counter.time_enabled, 4); 369 ASSERT_EQ(counter.time_running, 6); 370 } 371 372 class StatCmdSummaryBuilderTest : public ::testing::Test { 373 protected: 374 void AddCounter(int event_id, pid_t tid, int cpu, int value, int time_enabled, int time_running) { 375 if (thread_map_.count(tid) == 0) { 376 ThreadInfo& thread = thread_map_[tid]; 377 thread.pid = thread.tid = tid; 378 thread.name = "thread" + std::to_string(tid); 379 } 380 if (event_id >= counters_.size()) { 381 counters_.resize(event_id + 1); 382 counters_[event_id].group_id = 0; 383 counters_[event_id].event_name = "event" + std::to_string(event_id); 384 } 385 CountersInfo& info = counters_[event_id]; 386 info.counters.resize(info.counters.size() + 1); 387 CounterInfo& counter = info.counters.back(); 388 counter.tid = tid; 389 counter.cpu = cpu; 390 counter.counter.id = 0; 391 counter.counter.value = value; 392 counter.counter.time_enabled = time_enabled; 393 counter.counter.time_running = time_running; 394 } 395 396 std::vector<CounterSummary> BuildSummary(bool report_per_thread, bool report_per_core) { 397 CounterSummaryBuilder builder(report_per_thread, report_per_core, false, thread_map_); 398 for (auto& info : counters_) { 399 builder.AddCountersForOneEventType(info); 400 } 401 return builder.Build(); 402 } 403 404 std::unordered_map<pid_t, ThreadInfo> thread_map_; 405 std::vector<CountersInfo> counters_; 406 }; 407 408 TEST_F(StatCmdSummaryBuilderTest, multiple_events) { 409 AddCounter(0, 0, 0, 1, 1, 1); 410 AddCounter(1, 0, 0, 2, 2, 2); 411 std::vector<CounterSummary> summaries = BuildSummary(false, false); 412 ASSERT_EQ(summaries.size(), 2); 413 ASSERT_EQ(summaries[0].type_name, "event0"); 414 ASSERT_EQ(summaries[0].count, 1); 415 ASSERT_NEAR(summaries[0].scale, 1.0, 1e-5); 416 ASSERT_EQ(summaries[1].type_name, "event1"); 417 ASSERT_EQ(summaries[1].count, 2); 418 ASSERT_NEAR(summaries[1].scale, 1.0, 1e-5); 419 } 420 421 TEST_F(StatCmdSummaryBuilderTest, default_aggregate) { 422 AddCounter(0, 0, 0, 1, 1, 1); 423 AddCounter(0, 0, 1, 1, 1, 1); 424 AddCounter(0, 1, 0, 1, 1, 1); 425 AddCounter(0, 1, 1, 2, 2, 1); 426 std::vector<CounterSummary> summaries = BuildSummary(false, false); 427 ASSERT_EQ(summaries.size(), 1); 428 ASSERT_EQ(summaries[0].count, 5); 429 ASSERT_NEAR(summaries[0].scale, 1.25, 1e-5); 430 } 431 432 TEST_F(StatCmdSummaryBuilderTest, per_thread_aggregate) { 433 AddCounter(0, 0, 0, 1, 1, 1); 434 AddCounter(0, 0, 1, 1, 1, 1); 435 AddCounter(0, 1, 0, 1, 1, 1); 436 AddCounter(0, 1, 1, 2, 2, 1); 437 std::vector<CounterSummary> summaries = BuildSummary(true, false); 438 ASSERT_EQ(summaries.size(), 2); 439 ASSERT_EQ(summaries[0].thread->tid, 1); 440 ASSERT_EQ(summaries[0].cpu, -1); 441 ASSERT_EQ(summaries[0].count, 3); 442 ASSERT_NEAR(summaries[0].scale, 1.5, 1e-5); 443 ASSERT_EQ(summaries[1].thread->tid, 0); 444 ASSERT_EQ(summaries[0].cpu, -1); 445 ASSERT_EQ(summaries[1].count, 2); 446 ASSERT_NEAR(summaries[1].scale, 1.0, 1e-5); 447 } 448 449 TEST_F(StatCmdSummaryBuilderTest, per_core_aggregate) { 450 AddCounter(0, 0, 0, 1, 1, 1); 451 AddCounter(0, 0, 1, 1, 1, 1); 452 AddCounter(0, 1, 0, 1, 1, 1); 453 AddCounter(0, 1, 1, 2, 2, 1); 454 std::vector<CounterSummary> summaries = BuildSummary(false, true); 455 ASSERT_EQ(summaries.size(), 2); 456 ASSERT_TRUE(summaries[0].thread == nullptr); 457 ASSERT_EQ(summaries[0].cpu, 1); 458 ASSERT_EQ(summaries[0].count, 3); 459 ASSERT_NEAR(summaries[0].scale, 1.5, 1e-5); 460 ASSERT_TRUE(summaries[1].thread == nullptr); 461 ASSERT_EQ(summaries[1].cpu, 0); 462 ASSERT_EQ(summaries[1].count, 2); 463 ASSERT_NEAR(summaries[1].scale, 1.0, 1e-5); 464 } 465 466 TEST_F(StatCmdSummaryBuilderTest, per_thread_core_aggregate) { 467 AddCounter(0, 0, 0, 1, 1, 1); 468 AddCounter(0, 0, 1, 2, 1, 1); 469 AddCounter(0, 1, 0, 3, 1, 1); 470 AddCounter(0, 1, 1, 4, 2, 1); 471 std::vector<CounterSummary> summaries = BuildSummary(true, true); 472 ASSERT_EQ(summaries.size(), 4); 473 ASSERT_EQ(summaries[0].thread->tid, 1); 474 ASSERT_EQ(summaries[0].cpu, 1); 475 ASSERT_EQ(summaries[0].count, 4); 476 ASSERT_NEAR(summaries[0].scale, 2.0, 1e-5); 477 ASSERT_EQ(summaries[1].thread->tid, 1); 478 ASSERT_EQ(summaries[1].cpu, 0); 479 ASSERT_EQ(summaries[1].count, 3); 480 ASSERT_NEAR(summaries[1].scale, 1.0, 1e-5); 481 ASSERT_EQ(summaries[2].thread->tid, 0); 482 ASSERT_EQ(summaries[2].cpu, 1); 483 ASSERT_EQ(summaries[2].count, 2); 484 ASSERT_NEAR(summaries[2].scale, 1.0, 1e-5); 485 ASSERT_EQ(summaries[3].thread->tid, 0); 486 ASSERT_EQ(summaries[3].cpu, 0); 487 ASSERT_EQ(summaries[3].count, 1); 488 ASSERT_NEAR(summaries[3].scale, 1.0, 1e-5); 489 } 490 491 class StatCmdSummariesTest : public ::testing::Test { 492 protected: 493 void AddSummary(const std::string event_name, pid_t tid, int cpu, uint64_t count, 494 uint64_t runtime_in_ns) { 495 ThreadInfo* thread = nullptr; 496 if (tid != -1) { 497 thread = &thread_map_[tid]; 498 } 499 summary_v_.emplace_back(event_name, "", 0, thread, cpu, count, runtime_in_ns, 1.0, false, 500 false); 501 } 502 503 const std::string* GetComment(size_t index) { 504 if (!summaries_) { 505 summaries_.reset(new CounterSummaries(std::move(summary_v_), false)); 506 summaries_->GenerateComments(1.0); 507 } 508 if (index < summaries_->Summaries().size()) { 509 return &(summaries_->Summaries()[index].comment); 510 } 511 return nullptr; 512 } 513 514 std::unordered_map<pid_t, ThreadInfo> thread_map_; 515 std::vector<CounterSummary> summary_v_; 516 std::unique_ptr<CounterSummaries> summaries_; 517 }; 518 519 TEST_F(StatCmdSummariesTest, task_clock_comment) { 520 AddSummary("task-clock", -1, -1, 1e9, 0); 521 AddSummary("task-clock", 0, -1, 2e9, 0); 522 AddSummary("task-clock", -1, 0, 0.5e9, 0); 523 AddSummary("task-clock", 1, 1, 3e9, 0); 524 ASSERT_EQ(*GetComment(0), "1.000000 cpus used"); 525 ASSERT_EQ(*GetComment(1), "2.000000 cpus used"); 526 ASSERT_EQ(*GetComment(2), "0.500000 cpus used"); 527 ASSERT_EQ(*GetComment(3), "3.000000 cpus used"); 528 } 529 530 TEST_F(StatCmdSummariesTest, cpu_cycles_comment) { 531 AddSummary("cpu-cycles", -1, -1, 100, 100); 532 AddSummary("cpu-cycles", 0, -1, 200, 100); 533 AddSummary("cpu-cycles", -1, 0, 50, 100); 534 AddSummary("cpu-cycles", 1, 1, 300, 100); 535 ASSERT_EQ(*GetComment(0), "1.000000 GHz"); 536 ASSERT_EQ(*GetComment(1), "2.000000 GHz"); 537 ASSERT_EQ(*GetComment(2), "0.500000 GHz"); 538 ASSERT_EQ(*GetComment(3), "3.000000 GHz"); 539 } 540 541 TEST_F(StatCmdSummariesTest, rate_comment) { 542 AddSummary("branch-misses", -1, -1, 1e9, 1e9); 543 AddSummary("branch-misses", 0, -1, 1e6, 1e9); 544 AddSummary("branch-misses", -1, 0, 1e3, 1e9); 545 AddSummary("branch-misses", 1, 1, 1, 1e9); 546 ASSERT_EQ(*GetComment(0), "1.000 G/sec"); 547 ASSERT_EQ(*GetComment(1), "1.000 M/sec"); 548 ASSERT_EQ(*GetComment(2), "1.000 K/sec"); 549 ASSERT_EQ(*GetComment(3), "1.000 /sec"); 550 }