Add old generation allocation throughput computation.
authorulan <ulan@chromium.org>
Tue, 26 May 2015 11:51:18 +0000 (04:51 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 26 May 2015 11:51:28 +0000 (11:51 +0000)
BUG=chromium:492021
LOG=n

Review URL: https://codereview.chromium.org/1154873003

Cr-Commit-Position: refs/heads/master@{#28623}

src/heap/gc-idle-time-handler.cc
src/heap/gc-idle-time-handler.h
src/heap/gc-tracer.cc
src/heap/gc-tracer.h
src/heap/heap.cc
src/heap/heap.h
test/cctest/test-heap.cc

index 86587c6..496d7a0 100644 (file)
@@ -60,8 +60,8 @@ void GCIdleTimeHandler::HeapState::Print() {
   PrintF("new_space_capacity=%" V8_PTR_PREFIX "d ", new_space_capacity);
   PrintF("new_space_allocation_throughput=%" V8_PTR_PREFIX "d ",
          new_space_allocation_throughput_in_bytes_per_ms);
-  PrintF("current_new_space_allocation_throughput=%" V8_PTR_PREFIX "d",
-         current_new_space_allocation_throughput_in_bytes_per_ms);
+  PrintF("current_allocation_throughput=%" V8_PTR_PREFIX "d",
+         current_allocation_throughput_in_bytes_per_ms);
 }
 
 
index e5b671c..c370174 100644 (file)
@@ -188,7 +188,7 @@ class GCIdleTimeHandler {
     size_t used_new_space_size;
     size_t new_space_capacity;
     size_t new_space_allocation_throughput_in_bytes_per_ms;
-    size_t current_new_space_allocation_throughput_in_bytes_per_ms;
+    size_t current_allocation_throughput_in_bytes_per_ms;
   };
 
   GCIdleTimeHandler()
index 815baa4..4395ac5 100644 (file)
@@ -99,10 +99,12 @@ GCTracer::GCTracer(Heap* heap)
       longest_incremental_marking_step_(0.0),
       cumulative_marking_duration_(0.0),
       cumulative_sweeping_duration_(0.0),
-      new_space_allocation_time_ms_(0.0),
+      allocation_time_ms_(0.0),
       new_space_allocation_counter_bytes_(0),
-      new_space_allocation_duration_since_gc_(0.0),
+      old_generation_allocation_counter_bytes_(0),
+      allocation_duration_since_gc_(0.0),
       new_space_allocation_in_bytes_since_gc_(0),
+      old_generation_allocation_in_bytes_since_gc_(0),
       start_counter_(0) {
   current_ = Event(Event::START, NULL, NULL);
   current_.end_time = base::OS::TimeCurrentMillis();
@@ -117,7 +119,8 @@ void GCTracer::Start(GarbageCollector collector, const char* gc_reason,
 
   previous_ = current_;
   double start_time = heap_->MonotonicallyIncreasingTimeInMs();
-  SampleNewSpaceAllocation(start_time, heap_->NewSpaceAllocationCounter());
+  SampleAllocation(start_time, heap_->NewSpaceAllocationCounter(),
+                   heap_->OldGenerationAllocationCounter());
   if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR)
     previous_incremental_mark_compactor_event_ = current_;
 
@@ -183,7 +186,7 @@ void GCTracer::Stop(GarbageCollector collector) {
   current_.end_memory_size = heap_->isolate()->memory_allocator()->Size();
   current_.end_holes_size = CountTotalHolesSize(heap_);
 
-  AddNewSpaceAllocation(current_.end_time);
+  AddAllocation(current_.end_time);
 
   int committed_memory = static_cast<int>(heap_->CommittedMemory() / KB);
   int used_memory = static_cast<int>(current_.end_object_size / KB);
@@ -257,37 +260,49 @@ void GCTracer::Stop(GarbageCollector collector) {
 }
 
 
-void GCTracer::SampleNewSpaceAllocation(double current_ms,
-                                        size_t counter_bytes) {
-  if (new_space_allocation_time_ms_ == 0) {
+void GCTracer::SampleAllocation(double current_ms,
+                                size_t new_space_counter_bytes,
+                                size_t old_generation_counter_bytes) {
+  if (allocation_time_ms_ == 0) {
     // It is the first sample.
-    new_space_allocation_time_ms_ = current_ms;
-    new_space_allocation_counter_bytes_ = counter_bytes;
+    allocation_time_ms_ = current_ms;
+    new_space_allocation_counter_bytes_ = new_space_counter_bytes;
+    old_generation_allocation_counter_bytes_ = old_generation_counter_bytes;
     return;
   }
   // This assumes that counters are unsigned integers so that the subtraction
   // below works even if the new counter is less then the old counter.
-  size_t allocated_bytes = counter_bytes - new_space_allocation_counter_bytes_;
-  double duration = current_ms - new_space_allocation_time_ms_;
+  size_t new_space_allocated_bytes =
+      new_space_counter_bytes - new_space_allocation_counter_bytes_;
+  size_t old_generation_allocated_bytes =
+      old_generation_counter_bytes - old_generation_allocation_counter_bytes_;
+  double duration = current_ms - allocation_time_ms_;
   const double kMinDurationMs = 1;
   if (duration < kMinDurationMs) {
     // Do not sample small durations to avoid precision errors.
     return;
   }
-  new_space_allocation_time_ms_ = current_ms;
-  new_space_allocation_counter_bytes_ = counter_bytes;
-  new_space_allocation_duration_since_gc_ += duration;
-  new_space_allocation_in_bytes_since_gc_ += allocated_bytes;
+  allocation_time_ms_ = current_ms;
+  new_space_allocation_counter_bytes_ = new_space_counter_bytes;
+  old_generation_allocation_counter_bytes_ = old_generation_counter_bytes;
+  allocation_duration_since_gc_ += duration;
+  new_space_allocation_in_bytes_since_gc_ += new_space_allocated_bytes;
+  old_generation_allocation_in_bytes_since_gc_ +=
+      old_generation_allocated_bytes;
 }
 
 
-void GCTracer::AddNewSpaceAllocation(double current_ms) {
-  new_space_allocation_time_ms_ = current_ms;
+void GCTracer::AddAllocation(double current_ms) {
+  allocation_time_ms_ = current_ms;
+  new_space_allocation_events_.push_front(AllocationEvent(
+      allocation_duration_since_gc_, new_space_allocation_in_bytes_since_gc_));
   allocation_events_.push_front(
-      AllocationEvent(new_space_allocation_duration_since_gc_,
-                      new_space_allocation_in_bytes_since_gc_));
-  new_space_allocation_duration_since_gc_ = 0;
+      AllocationEvent(allocation_duration_since_gc_,
+                      new_space_allocation_in_bytes_since_gc_ +
+                          old_generation_allocation_in_bytes_since_gc_));
+  allocation_duration_since_gc_ = 0;
   new_space_allocation_in_bytes_since_gc_ = 0;
+  old_generation_allocation_in_bytes_since_gc_ = 0;
 }
 
 
@@ -583,10 +598,12 @@ intptr_t GCTracer::FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()
 
 size_t GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond() const {
   size_t bytes = new_space_allocation_in_bytes_since_gc_;
-  double durations = new_space_allocation_duration_since_gc_;
-  AllocationEventBuffer::const_iterator iter = allocation_events_.begin();
+  double durations = allocation_duration_since_gc_;
+  AllocationEventBuffer::const_iterator iter =
+      new_space_allocation_events_.begin();
   const size_t max_bytes = static_cast<size_t>(-1);
-  while (iter != allocation_events_.end() && bytes < max_bytes - bytes) {
+  while (iter != new_space_allocation_events_.end() &&
+         bytes < max_bytes - bytes) {
     bytes += iter->allocation_in_bytes_;
     durations += iter->duration_;
     ++iter;
@@ -598,9 +615,10 @@ size_t GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond() const {
 }
 
 
-size_t GCTracer::NewSpaceAllocatedBytesInLast(double time_ms) const {
-  size_t bytes = new_space_allocation_in_bytes_since_gc_;
-  double durations = new_space_allocation_duration_since_gc_;
+size_t GCTracer::AllocatedBytesInLast(double time_ms) const {
+  size_t bytes = new_space_allocation_in_bytes_since_gc_ +
+                 old_generation_allocation_in_bytes_since_gc_;
+  double durations = allocation_duration_since_gc_;
   AllocationEventBuffer::const_iterator iter = allocation_events_.begin();
   const size_t max_bytes = static_cast<size_t>(-1);
   while (iter != allocation_events_.end() && bytes < max_bytes - bytes &&
@@ -618,10 +636,9 @@ size_t GCTracer::NewSpaceAllocatedBytesInLast(double time_ms) const {
 }
 
 
-size_t GCTracer::CurrentNewSpaceAllocationThroughputInBytesPerMillisecond()
-    const {
+size_t GCTracer::CurrentAllocationThroughputInBytesPerMillisecond() const {
   static const double kThroughputTimeFrame = 5000;
-  size_t allocated_bytes = NewSpaceAllocatedBytesInLast(kThroughputTimeFrame);
+  size_t allocated_bytes = AllocatedBytesInLast(kThroughputTimeFrame);
   if (allocated_bytes == 0) return 0;
   return static_cast<size_t>((allocated_bytes / kThroughputTimeFrame) + 1);
 }
index 7fb6a76..e16f5d5 100644 (file)
@@ -296,10 +296,11 @@ class GCTracer {
   void Stop(GarbageCollector collector);
 
   // Sample and accumulate bytes allocated since the last GC.
-  void SampleNewSpaceAllocation(double current_ms, size_t counter_bytes);
+  void SampleAllocation(double current_ms, size_t new_space_counter_bytes,
+                        size_t old_generation_counter_bytes);
 
   // Log the accumulated new space allocation bytes.
-  void AddNewSpaceAllocation(double current_ms);
+  void AddAllocation(double current_ms);
 
   void AddContextDisposalTime(double time);
 
@@ -385,14 +386,14 @@ class GCTracer {
   // Returns 0 if no allocation events have been recorded.
   size_t NewSpaceAllocationThroughputInBytesPerMillisecond() const;
 
-  // Bytes allocated in new space in the specified time.
+  // Bytes allocated in heap in the specified time.
   // Returns 0 if no allocation events have been recorded.
-  size_t NewSpaceAllocatedBytesInLast(double time_ms) const;
+  size_t AllocatedBytesInLast(double time_ms) const;
 
-  // Allocation throughput in the new space in bytes/milliseconds in
+  // Allocation throughput in heap in bytes/milliseconds in
   // the last five seconds.
   // Returns 0 if no allocation events have been recorded.
-  size_t CurrentNewSpaceAllocationThroughputInBytesPerMillisecond() const;
+  size_t CurrentAllocationThroughputInBytesPerMillisecond() const;
 
   // Computes the context disposal rate in milliseconds. It takes the time
   // frame of the first recorded context disposal to the current time and
@@ -459,6 +460,7 @@ class GCTracer {
   EventBuffer incremental_mark_compactor_events_;
 
   // RingBuffer for allocation events.
+  AllocationEventBuffer new_space_allocation_events_;
   AllocationEventBuffer allocation_events_;
 
   // RingBuffer for context disposal events.
@@ -498,12 +500,14 @@ class GCTracer {
   double cumulative_sweeping_duration_;
 
   // Timestamp and allocation counter at the last sampled allocation event.
-  double new_space_allocation_time_ms_;
+  double allocation_time_ms_;
   size_t new_space_allocation_counter_bytes_;
+  size_t old_generation_allocation_counter_bytes_;
 
   // Accumulated duration and allocated bytes since the last GC.
-  double new_space_allocation_duration_since_gc_;
+  double allocation_duration_since_gc_;
   size_t new_space_allocation_in_bytes_since_gc_;
+  size_t old_generation_allocation_in_bytes_since_gc_;
 
   // Counts how many tracers were started without stopping.
   int start_counter_;
index e54ec1e..21e3b3b 100644 (file)
@@ -142,6 +142,8 @@ Heap::Heap()
       full_codegen_bytes_generated_(0),
       crankshaft_codegen_bytes_generated_(0),
       new_space_allocation_counter_(0),
+      old_generation_allocation_counter_(0),
+      old_generation_size_at_last_gc_(0),
       gcs_since_last_deopt_(0),
       allocation_sites_scratchpad_length_(0),
       promotion_queue_(this),
@@ -467,6 +469,7 @@ void Heap::GarbageCollectionPrologue() {
   }
   CheckNewSpaceExpansionCriteria();
   UpdateNewSpaceAllocationCounter();
+  UpdateOldGenerationAllocationCounter();
 }
 
 
@@ -735,7 +738,7 @@ void Heap::GarbageCollectionEpilogue() {
   last_gc_time_ = MonotonicallyIncreasingTimeInMs();
 
   ReduceNewSpaceSize(
-      tracer()->CurrentNewSpaceAllocationThroughputInBytesPerMillisecond());
+      tracer()->CurrentAllocationThroughputInBytesPerMillisecond());
 }
 
 
@@ -1223,6 +1226,10 @@ bool Heap::PerformGarbageCollection(
     Scavenge();
   }
 
+  // This should be updated before PostGarbageCollectionProcessing, which can
+  // cause another GC.
+  old_generation_size_at_last_gc_ = PromotedSpaceSizeOfObjects();
+
   UpdateSurvivalStatistics(start_new_space_size);
   ConfigureInitialOldGenerationSize();
 
@@ -4642,11 +4649,11 @@ GCIdleTimeHandler::HeapState Heap::ComputeHeapState() {
   heap_state.new_space_capacity = new_space_.Capacity();
   heap_state.new_space_allocation_throughput_in_bytes_per_ms =
       tracer()->NewSpaceAllocationThroughputInBytesPerMillisecond();
-  heap_state.current_new_space_allocation_throughput_in_bytes_per_ms =
-      tracer()->CurrentNewSpaceAllocationThroughputInBytesPerMillisecond();
+  heap_state.current_allocation_throughput_in_bytes_per_ms =
+      tracer()->CurrentAllocationThroughputInBytesPerMillisecond();
   intptr_t limit = old_generation_allocation_limit_;
   if (HasLowAllocationRate(
-          heap_state.current_new_space_allocation_throughput_in_bytes_per_ms)) {
+          heap_state.current_allocation_throughput_in_bytes_per_ms)) {
     limit = idle_old_generation_allocation_limit_;
   }
   heap_state.can_start_incremental_marking =
@@ -4800,7 +4807,8 @@ bool Heap::IdleNotification(double deadline_in_seconds) {
       GCIdleTimeHandler::kMaxFrameRenderingIdleTime;
 
   if (is_long_idle_notification) {
-    tracer()->SampleNewSpaceAllocation(start_ms, NewSpaceAllocationCounter());
+    tracer()->SampleAllocation(start_ms, NewSpaceAllocationCounter(),
+                               OldGenerationAllocationCounter());
   }
 
   GCIdleTimeHandler::HeapState heap_state = ComputeHeapState();
index e5f7fe9..ad5ef66 100644 (file)
@@ -1325,6 +1325,23 @@ class Heap {
     new_space_allocation_counter_ = new_value;
   }
 
+  void UpdateOldGenerationAllocationCounter() {
+    old_generation_allocation_counter_ = OldGenerationAllocationCounter();
+  }
+
+  size_t OldGenerationAllocationCounter() {
+    return old_generation_allocation_counter_ + PromotedSinceLastGC();
+  }
+
+  // This should be used only for testing.
+  void set_old_generation_allocation_counter(size_t new_value) {
+    old_generation_allocation_counter_ = new_value;
+  }
+
+  size_t PromotedSinceLastGC() {
+    return PromotedSpaceSizeOfObjects() - old_generation_size_at_last_gc_;
+  }
+
   // Update GC statistics that are tracked on the Heap.
   void UpdateCumulativeGCStatistics(double duration, double spent_in_mutator,
                                     double marking_time);
@@ -2206,6 +2223,14 @@ class Heap {
   // NewSpaceAllocationCounter() function.
   size_t new_space_allocation_counter_;
 
+  // This counter is increased before each GC and never reset. To
+  // account for the bytes allocated since the last GC, use the
+  // OldGenerationAllocationCounter() function.
+  size_t old_generation_allocation_counter_;
+
+  // The size of objects in old generation after the last MarkCompact GC.
+  size_t old_generation_size_at_last_gc_;
+
   // If the --deopt_every_n_garbage_collections flag is set to a positive value,
   // this variable holds the number of garbage collections since the last
   // deoptimization triggered by garbage collection.
index 482d111..b817886 100644 (file)
@@ -5439,7 +5439,7 @@ TEST(Regress1878) {
 }
 
 
-void AllocateInNewSpace(Isolate* isolate, size_t bytes) {
+void AllocateInSpace(Isolate* isolate, size_t bytes, AllocationSpace space) {
   CHECK(bytes >= FixedArray::kHeaderSize);
   CHECK(bytes % kPointerSize == 0);
   Factory* factory = isolate->factory();
@@ -5447,8 +5447,9 @@ void AllocateInNewSpace(Isolate* isolate, size_t bytes) {
   AlwaysAllocateScope always_allocate(isolate);
   int elements =
       static_cast<int>((bytes - FixedArray::kHeaderSize) / kPointerSize);
-  Handle<FixedArray> array = factory->NewFixedArray(elements, NOT_TENURED);
-  CHECK(isolate->heap()->InNewSpace(*array));
+  Handle<FixedArray> array = factory->NewFixedArray(
+      elements, space == NEW_SPACE ? NOT_TENURED : TENURED);
+  CHECK((space == NEW_SPACE) == isolate->heap()->InNewSpace(*array));
   CHECK_EQ(bytes, static_cast<size_t>(array->Size()));
 }
 
@@ -5461,7 +5462,7 @@ TEST(NewSpaceAllocationCounter) {
   size_t counter1 = heap->NewSpaceAllocationCounter();
   heap->CollectGarbage(NEW_SPACE);
   const size_t kSize = 1024;
-  AllocateInNewSpace(isolate, kSize);
+  AllocateInSpace(isolate, kSize, NEW_SPACE);
   size_t counter2 = heap->NewSpaceAllocationCounter();
   CHECK_EQ(kSize, counter2 - counter1);
   heap->CollectGarbage(NEW_SPACE);
@@ -5472,7 +5473,7 @@ TEST(NewSpaceAllocationCounter) {
   heap->set_new_space_allocation_counter(max_counter - 10 * kSize);
   size_t start = heap->NewSpaceAllocationCounter();
   for (int i = 0; i < 20; i++) {
-    AllocateInNewSpace(isolate, kSize);
+    AllocateInSpace(isolate, kSize, NEW_SPACE);
     size_t counter = heap->NewSpaceAllocationCounter();
     CHECK_EQ(kSize, counter - start);
     start = counter;
@@ -5480,6 +5481,37 @@ TEST(NewSpaceAllocationCounter) {
 }
 
 
+TEST(OldSpaceAllocationCounter) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  size_t counter1 = heap->OldGenerationAllocationCounter();
+  heap->CollectGarbage(NEW_SPACE);
+  const size_t kSize = 1024;
+  AllocateInSpace(isolate, kSize, OLD_SPACE);
+  size_t counter2 = heap->OldGenerationAllocationCounter();
+  CHECK_EQ(kSize, counter2 - counter1);
+  heap->CollectGarbage(NEW_SPACE);
+  size_t counter3 = heap->OldGenerationAllocationCounter();
+  CHECK_EQ(0, counter3 - counter2);
+  AllocateInSpace(isolate, kSize, OLD_SPACE);
+  heap->CollectGarbage(OLD_SPACE);
+  size_t counter4 = heap->OldGenerationAllocationCounter();
+  CHECK_EQ(kSize, counter4 - counter3);
+  // Test counter overflow.
+  size_t max_counter = -1;
+  heap->set_old_generation_allocation_counter(max_counter - 10 * kSize);
+  size_t start = heap->OldGenerationAllocationCounter();
+  for (int i = 0; i < 20; i++) {
+    AllocateInSpace(isolate, kSize, OLD_SPACE);
+    size_t counter = heap->OldGenerationAllocationCounter();
+    CHECK_EQ(kSize, counter - start);
+    start = counter;
+  }
+}
+
+
 TEST(NewSpaceAllocationThroughput) {
   CcTest::InitializeVM();
   v8::HandleScope scope(CcTest::isolate());
@@ -5488,16 +5520,16 @@ TEST(NewSpaceAllocationThroughput) {
   GCTracer* tracer = heap->tracer();
   int time1 = 100;
   size_t counter1 = 1000;
-  tracer->SampleNewSpaceAllocation(time1, counter1);
+  tracer->SampleAllocation(time1, counter1, 0);
   int time2 = 200;
   size_t counter2 = 2000;
-  tracer->SampleNewSpaceAllocation(time2, counter2);
+  tracer->SampleAllocation(time2, counter2, 0);
   size_t throughput =
       tracer->NewSpaceAllocationThroughputInBytesPerMillisecond();
   CHECK_EQ((counter2 - counter1) / (time2 - time1), throughput);
   int time3 = 1000;
   size_t counter3 = 30000;
-  tracer->SampleNewSpaceAllocation(time3, counter3);
+  tracer->SampleAllocation(time3, counter3, 0);
   throughput = tracer->NewSpaceAllocationThroughputInBytesPerMillisecond();
   CHECK_EQ((counter3 - counter1) / (time3 - time1), throughput);
 }
@@ -5511,16 +5543,16 @@ TEST(NewSpaceAllocationThroughput2) {
   GCTracer* tracer = heap->tracer();
   int time1 = 100;
   size_t counter1 = 1000;
-  tracer->SampleNewSpaceAllocation(time1, counter1);
+  tracer->SampleAllocation(time1, counter1, 0);
   int time2 = 200;
   size_t counter2 = 2000;
-  tracer->SampleNewSpaceAllocation(time2, counter2);
-  size_t bytes = tracer->NewSpaceAllocatedBytesInLast(1000);
+  tracer->SampleAllocation(time2, counter2, 0);
+  size_t bytes = tracer->AllocatedBytesInLast(1000);
   CHECK_EQ(10000, bytes);
   int time3 = 1000;
   size_t counter3 = 30000;
-  tracer->SampleNewSpaceAllocation(time3, counter3);
-  bytes = tracer->NewSpaceAllocatedBytesInLast(100);
+  tracer->SampleAllocation(time3, counter3, 0);
+  bytes = tracer->AllocatedBytesInLast(100);
   CHECK_EQ((counter3 - counter1) * 100 / (time3 - time1), bytes);
 }
 
@@ -5564,3 +5596,47 @@ TEST(MessageObjectLeak) {
 
   CompileRun(test);
 }
+
+
+TEST(OldGenerationAllocationThroughput) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  GCTracer* tracer = heap->tracer();
+  int time1 = 100;
+  size_t counter1 = 1000;
+  tracer->SampleAllocation(time1, 0, counter1);
+  int time2 = 200;
+  size_t counter2 = 2000;
+  tracer->SampleAllocation(time2, 0, counter2);
+  size_t bytes = tracer->AllocatedBytesInLast(1000);
+  CHECK_EQ(10000, bytes);
+  int time3 = 1000;
+  size_t counter3 = 30000;
+  tracer->SampleAllocation(time3, 0, counter3);
+  bytes = tracer->AllocatedBytesInLast(100);
+  CHECK_EQ((counter3 - counter1) * 100 / (time3 - time1), bytes);
+}
+
+
+TEST(AllocationThroughput) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  GCTracer* tracer = heap->tracer();
+  int time1 = 100;
+  size_t counter1 = 1000;
+  tracer->SampleAllocation(time1, counter1, counter1);
+  int time2 = 200;
+  size_t counter2 = 2000;
+  tracer->SampleAllocation(time2, counter2, counter2);
+  size_t bytes = tracer->AllocatedBytesInLast(1000);
+  CHECK_EQ(20000, bytes);
+  int time3 = 1000;
+  size_t counter3 = 30000;
+  tracer->SampleAllocation(time3, counter3, counter3);
+  bytes = tracer->AllocatedBytesInLast(100);
+  CHECK_EQ(2 * (counter3 - counter1) * 100 / (time3 - time1), bytes);
+}