From 67d57de7d352476e67fee57be619f789cbf7f859 Mon Sep 17 00:00:00 2001 From: dtanmay <16020637+tanmaydas82@users.noreply.github.com> Date: Fri, 29 Jul 2022 18:42:12 -0700 Subject: [PATCH 1/6] Microprofiler can now output logs for benchmarks in the csv format. --- tensorflow/lite/micro/BUILD | 1 + tensorflow/lite/micro/micro_profiler.cc | 54 +++++++++++++++++++++++++ tensorflow/lite/micro/micro_profiler.h | 12 ++++++ 3 files changed, 67 insertions(+) diff --git a/tensorflow/lite/micro/BUILD b/tensorflow/lite/micro/BUILD index 1174231c9c3..62ee95531c8 100644 --- a/tensorflow/lite/micro/BUILD +++ b/tensorflow/lite/micro/BUILD @@ -317,6 +317,7 @@ cc_library( ], copts = micro_copts(), deps = [ + ":micro_compatibility", ":micro_error_reporter", ":micro_time", "//tensorflow/lite/kernels/internal:compatibility", diff --git a/tensorflow/lite/micro/micro_profiler.cc b/tensorflow/lite/micro/micro_profiler.cc index 72f3d37fd09..aadbe025f46 100644 --- a/tensorflow/lite/micro/micro_profiler.cc +++ b/tensorflow/lite/micro/micro_profiler.cc @@ -67,4 +67,58 @@ void MicroProfiler::LogCsv() const { #endif } +void MicroProfiler::LogTicksPerTagCsv() { +#if !defined(TF_LITE_STRIP_ERROR_STRINGS) + MicroPrintf( + "\"Unique Ops in the Graph\",\"Total Ticks (all instances of the Op)\""); + uint totalTicks = 0; + for (int i = 0; i < num_events_; ++i) { + uint32_t ticks = end_ticks_[i] - start_ticks_[i]; + int position = FindExistingOrNextPosition(tags_[i]); + total_ticks_per_tag[position].tag = tags_[i]; + total_ticks_per_tag[position].ticks = + total_ticks_per_tag[position].ticks + ticks; + totalTicks += ticks; + } + + for (int i = 0; i < num_events_; ++i) { + ticks_per_tag ticksPerTag = total_ticks_per_tag[i]; + if (ticksPerTag.tag == nullptr) { + break; + } + MicroPrintf("%s,%d", ticksPerTag.tag, ticksPerTag.ticks); + } + MicroPrintf("total,%d", totalTicks); + +#endif +} + +int MicroProfiler::FindExistingOrNextPosition(const char* tagName) { + int pos = 0; + for (; pos < num_events_; pos++) { + ticks_per_tag ticksPerTag = total_ticks_per_tag[pos]; + if (ticksPerTag.tag == nullptr) { + return pos; + } else { + const char* tag = ticksPerTag.tag; + const char* tagName_t = tagName; + bool matched = true; + while ((*tag != '\0') && (*tagName_t != '\0')) { + if (((*tag) == (*tagName_t))) { + ++tag; + ++tagName_t; + } else { + matched = false; + break; + } + } + + if (matched) { + return pos; + } + } + } + return pos; +} + } // namespace tflite diff --git a/tensorflow/lite/micro/micro_profiler.h b/tensorflow/lite/micro/micro_profiler.h index 41f41a359de..9461ff8c404 100644 --- a/tensorflow/lite/micro/micro_profiler.h +++ b/tensorflow/lite/micro/micro_profiler.h @@ -61,6 +61,10 @@ class MicroProfiler { // Separated Value) form. void LogCsv() const; + // Prints the profiling information of each of the tags in CSV (Comma + // Separated Value) form. + void LogTicksPerTagCsv(); + private: // Maximum number of events that this class can keep track of. If we call // AddEvent more than kMaxEvents number of times, then the oldest event's @@ -72,6 +76,14 @@ class MicroProfiler { uint32_t end_ticks_[kMaxEvents]; int num_events_ = 0; + struct ticks_per_tag { + const char* tag; + uint32_t ticks; + }; + ticks_per_tag total_ticks_per_tag[kMaxEvents]; + + int FindExistingOrNextPosition(const char* tagName); + TF_LITE_REMOVE_VIRTUAL_DELETE; }; From e59bceb3ecfe7b03ea13181027be1b729152507d Mon Sep 17 00:00:00 2001 From: dtanmay <16020637+tanmaydas82@users.noreply.github.com> Date: Fri, 29 Jul 2022 18:47:43 -0700 Subject: [PATCH 2/6] Fix failing tests. --- tensorflow/lite/micro/micro_profiler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/lite/micro/micro_profiler.cc b/tensorflow/lite/micro/micro_profiler.cc index aadbe025f46..37667b5cc65 100644 --- a/tensorflow/lite/micro/micro_profiler.cc +++ b/tensorflow/lite/micro/micro_profiler.cc @@ -71,7 +71,7 @@ void MicroProfiler::LogTicksPerTagCsv() { #if !defined(TF_LITE_STRIP_ERROR_STRINGS) MicroPrintf( "\"Unique Ops in the Graph\",\"Total Ticks (all instances of the Op)\""); - uint totalTicks = 0; + int totalTicks = 0; for (int i = 0; i < num_events_; ++i) { uint32_t ticks = end_ticks_[i] - start_ticks_[i]; int position = FindExistingOrNextPosition(tags_[i]); From f04b0ec26b9252c78c52fd2c4649857c4a407315 Mon Sep 17 00:00:00 2001 From: dtanmay <16020637+tanmaydas82@users.noreply.github.com> Date: Fri, 29 Jul 2022 19:05:28 -0700 Subject: [PATCH 3/6] Renaming some variables. --- tensorflow/lite/micro/micro_profiler.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tensorflow/lite/micro/micro_profiler.cc b/tensorflow/lite/micro/micro_profiler.cc index 37667b5cc65..f6fe08a27ad 100644 --- a/tensorflow/lite/micro/micro_profiler.cc +++ b/tensorflow/lite/micro/micro_profiler.cc @@ -100,13 +100,13 @@ int MicroProfiler::FindExistingOrNextPosition(const char* tagName) { if (ticksPerTag.tag == nullptr) { return pos; } else { - const char* tag = ticksPerTag.tag; - const char* tagName_t = tagName; + const char* currentTagName_t = ticksPerTag.tag; + const char* newTagName_t = tagName; bool matched = true; - while ((*tag != '\0') && (*tagName_t != '\0')) { - if (((*tag) == (*tagName_t))) { - ++tag; - ++tagName_t; + while ((*currentTagName_t != '\0') && (*newTagName_t != '\0')) { + if (((*currentTagName_t) == (*newTagName_t))) { + ++currentTagName_t; + ++newTagName_t; } else { matched = false; break; From decb722c643f77568f41ec7ae68bdeb90febca5e Mon Sep 17 00:00:00 2001 From: dtanmay <16020637+tanmaydas82@users.noreply.github.com> Date: Mon, 1 Aug 2022 12:34:21 -0700 Subject: [PATCH 4/6] Incorporating all the review comments. --- tensorflow/lite/micro/micro_profiler.cc | 33 +++++++++++++++---------- tensorflow/lite/micro/micro_profiler.h | 12 ++++++--- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/tensorflow/lite/micro/micro_profiler.cc b/tensorflow/lite/micro/micro_profiler.cc index f6fe08a27ad..d71add1c4e6 100644 --- a/tensorflow/lite/micro/micro_profiler.cc +++ b/tensorflow/lite/micro/micro_profiler.cc @@ -70,38 +70,45 @@ void MicroProfiler::LogCsv() const { void MicroProfiler::LogTicksPerTagCsv() { #if !defined(TF_LITE_STRIP_ERROR_STRINGS) MicroPrintf( - "\"Unique Ops in the Graph\",\"Total Ticks (all instances of the Op)\""); - int totalTicks = 0; + "\"Unique Tag\",\"Total ticks across all events with that tag.\""); + int total_ticks = 0; for (int i = 0; i < num_events_; ++i) { uint32_t ticks = end_ticks_[i] - start_ticks_[i]; int position = FindExistingOrNextPosition(tags_[i]); total_ticks_per_tag[position].tag = tags_[i]; total_ticks_per_tag[position].ticks = total_ticks_per_tag[position].ticks + ticks; - totalTicks += ticks; + total_ticks += ticks; } for (int i = 0; i < num_events_; ++i) { - ticks_per_tag ticksPerTag = total_ticks_per_tag[i]; - if (ticksPerTag.tag == nullptr) { + TicksPerTag each_tag_entry = total_ticks_per_tag[i]; + if (each_tag_entry.tag == nullptr) { break; } - MicroPrintf("%s,%d", ticksPerTag.tag, ticksPerTag.ticks); + MicroPrintf("%s,%d", each_tag_entry.tag, each_tag_entry.ticks); } - MicroPrintf("total,%d", totalTicks); - + MicroPrintf("total,%d", total_ticks); #endif } -int MicroProfiler::FindExistingOrNextPosition(const char* tagName) { +/** + * This method finds a particular array element in the total_ticks_per_tag array + * with the matching tag_name passed in the method. If it can find a + * matching array element that has the same tag_name, then it will return the + * position of the matching element. But if it unable to find a matching element + * with the given tag_name, it will return the next available empty postion + * from the array. + */ +int MicroProfiler::FindExistingOrNextPosition(const char* tag_name) { int pos = 0; for (; pos < num_events_; pos++) { - ticks_per_tag ticksPerTag = total_ticks_per_tag[pos]; - if (ticksPerTag.tag == nullptr) { + TicksPerTag each_tag_entry = total_ticks_per_tag[pos]; + if (each_tag_entry.tag == nullptr) { return pos; } else { - const char* currentTagName_t = ticksPerTag.tag; - const char* newTagName_t = tagName; + const char* currentTagName_t = each_tag_entry.tag; + const char* newTagName_t = tag_name; bool matched = true; while ((*currentTagName_t != '\0') && (*newTagName_t != '\0')) { if (((*currentTagName_t) == (*newTagName_t))) { diff --git a/tensorflow/lite/micro/micro_profiler.h b/tensorflow/lite/micro/micro_profiler.h index 9461ff8c404..6e26bab33d6 100644 --- a/tensorflow/lite/micro/micro_profiler.h +++ b/tensorflow/lite/micro/micro_profiler.h @@ -61,8 +61,9 @@ class MicroProfiler { // Separated Value) form. void LogCsv() const; - // Prints the profiling information of each of the tags in CSV (Comma - // Separated Value) form. + // Prints total ticks for each unique tag in CSV format. + // Output will have one row for each unique tag along with the + // total ticks summed across all events with that particular tag. void LogTicksPerTagCsv(); private: @@ -76,11 +77,14 @@ class MicroProfiler { uint32_t end_ticks_[kMaxEvents]; int num_events_ = 0; - struct ticks_per_tag { + struct TicksPerTag { const char* tag; uint32_t ticks; }; - ticks_per_tag total_ticks_per_tag[kMaxEvents]; + // In practice, the number of tags will be much lower than the number of + // events. But it is theoretically possible that each event to be unique and + // hence we allow total_ticks_per_tag to have kMaxEvents entries. + TicksPerTag total_ticks_per_tag[kMaxEvents]; int FindExistingOrNextPosition(const char* tagName); From 483a5a4b21fa192fe7612b42be10b3c18b49865d Mon Sep 17 00:00:00 2001 From: dtanmay <16020637+tanmaydas82@users.noreply.github.com> Date: Tue, 2 Aug 2022 11:00:57 -0700 Subject: [PATCH 5/6] Incorporating review comments. --- tensorflow/lite/micro/micro_profiler.cc | 46 ++++++++++--------------- tensorflow/lite/micro/micro_profiler.h | 2 +- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/tensorflow/lite/micro/micro_profiler.cc b/tensorflow/lite/micro/micro_profiler.cc index d71add1c4e6..e4c2859d0de 100644 --- a/tensorflow/lite/micro/micro_profiler.cc +++ b/tensorflow/lite/micro/micro_profiler.cc @@ -16,6 +16,7 @@ limitations under the License. #include #include +#include #include "tensorflow/lite/kernels/internal/compatibility.h" #include "tensorflow/lite/micro/micro_error_reporter.h" @@ -74,7 +75,15 @@ void MicroProfiler::LogTicksPerTagCsv() { int total_ticks = 0; for (int i = 0; i < num_events_; ++i) { uint32_t ticks = end_ticks_[i] - start_ticks_[i]; + if (tags_[i] == nullptr) { + MicroPrintf("Event does not have a tag name."); + continue; + } int position = FindExistingOrNextPosition(tags_[i]); + if (position == -1) { + MicroPrintf("Number of tags exceeds the memory allocation."); + return; + } total_ticks_per_tag[position].tag = tags_[i]; total_ticks_per_tag[position].ticks = total_ticks_per_tag[position].ticks + ticks; @@ -92,40 +101,21 @@ void MicroProfiler::LogTicksPerTagCsv() { #endif } -/** - * This method finds a particular array element in the total_ticks_per_tag array - * with the matching tag_name passed in the method. If it can find a - * matching array element that has the same tag_name, then it will return the - * position of the matching element. But if it unable to find a matching element - * with the given tag_name, it will return the next available empty postion - * from the array. - */ +// This method finds a particular array element in the total_ticks_per_tag array +// with the matching tag_name passed in the method. If it can find a +// matching array element that has the same tag_name, then it will return the +// position of the matching element. But if it unable to find a matching element +// with the given tag_name, it will return the next available empty position +// from the array. int MicroProfiler::FindExistingOrNextPosition(const char* tag_name) { int pos = 0; for (; pos < num_events_; pos++) { TicksPerTag each_tag_entry = total_ticks_per_tag[pos]; - if (each_tag_entry.tag == nullptr) { + if (each_tag_entry.tag == nullptr || + strcmp(each_tag_entry.tag, tag_name) == 0) { return pos; - } else { - const char* currentTagName_t = each_tag_entry.tag; - const char* newTagName_t = tag_name; - bool matched = true; - while ((*currentTagName_t != '\0') && (*newTagName_t != '\0')) { - if (((*currentTagName_t) == (*newTagName_t))) { - ++currentTagName_t; - ++newTagName_t; - } else { - matched = false; - break; - } - } - - if (matched) { - return pos; - } } } - return pos; + return pos < num_events_ ? pos : -1; } - } // namespace tflite diff --git a/tensorflow/lite/micro/micro_profiler.h b/tensorflow/lite/micro/micro_profiler.h index 6e26bab33d6..1d04904531e 100644 --- a/tensorflow/lite/micro/micro_profiler.h +++ b/tensorflow/lite/micro/micro_profiler.h @@ -86,7 +86,7 @@ class MicroProfiler { // hence we allow total_ticks_per_tag to have kMaxEvents entries. TicksPerTag total_ticks_per_tag[kMaxEvents]; - int FindExistingOrNextPosition(const char* tagName); + int FindExistingOrNextPosition(const char* tag_name); TF_LITE_REMOVE_VIRTUAL_DELETE; }; From 09736e6693c0861a3ab3e32202fb70f0615f52d7 Mon Sep 17 00:00:00 2001 From: dtanmay <16020637+tanmaydas82@users.noreply.github.com> Date: Fri, 5 Aug 2022 15:00:33 -0700 Subject: [PATCH 6/6] Replaced the error logs with DCHECK. --- tensorflow/lite/micro/micro_profiler.cc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tensorflow/lite/micro/micro_profiler.cc b/tensorflow/lite/micro/micro_profiler.cc index e4c2859d0de..86b1ebbb5dc 100644 --- a/tensorflow/lite/micro/micro_profiler.cc +++ b/tensorflow/lite/micro/micro_profiler.cc @@ -75,15 +75,9 @@ void MicroProfiler::LogTicksPerTagCsv() { int total_ticks = 0; for (int i = 0; i < num_events_; ++i) { uint32_t ticks = end_ticks_[i] - start_ticks_[i]; - if (tags_[i] == nullptr) { - MicroPrintf("Event does not have a tag name."); - continue; - } + TFLITE_DCHECK(tags_[i] != nullptr); int position = FindExistingOrNextPosition(tags_[i]); - if (position == -1) { - MicroPrintf("Number of tags exceeds the memory allocation."); - return; - } + TFLITE_DCHECK(position >= 0); total_ticks_per_tag[position].tag = tags_[i]; total_ticks_per_tag[position].ticks = total_ticks_per_tag[position].ticks + ticks; @@ -95,9 +89,9 @@ void MicroProfiler::LogTicksPerTagCsv() { if (each_tag_entry.tag == nullptr) { break; } - MicroPrintf("%s,%d", each_tag_entry.tag, each_tag_entry.ticks); + MicroPrintf("%s, %d", each_tag_entry.tag, each_tag_entry.ticks); } - MicroPrintf("total,%d", total_ticks); + MicroPrintf("total number of ticks, %d", total_ticks); #endif }