Add micro timer interface and a default implementation.

PiperOrigin-RevId: 298971695
Change-Id: I9a532ca7073b55458c5f27e31bcb5869d7221706
This commit is contained in:
Nat Jeffries 2020-03-04 16:39:37 -08:00 committed by TensorFlower Gardener
parent a1f337ce7f
commit 1f04347d0d
6 changed files with 247 additions and 0 deletions

View File

@ -81,6 +81,19 @@ cc_library(
],
)
cc_library(
name = "micro_time",
srcs = [
"posix/micro_time.cc",
],
hdrs = [
"micro_time.h",
],
build_for_embedded = True,
copts = micro_copts(),
deps = ["//tensorflow/lite/c:common"],
)
cc_library(
name = "micro_utils",
srcs = [
@ -196,3 +209,14 @@ tflite_micro_cc_test(
"//tensorflow/lite/micro/testing:micro_test",
],
)
tflite_micro_cc_test(
name = "micro_time_test",
srcs = [
"micro_time_test.cc",
],
deps = [
":micro_time",
"//tensorflow/lite/micro/testing:micro_test",
],
)

View File

@ -0,0 +1,44 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Reference implementation of timer functions. Platforms are not required to
// implement these timer methods, but they are required to enable profiling.
// On platforms that have a POSIX stack or C library, it can be written using
// methods from <sys/time.h> or clock() from <time.h>.
// To add an equivalent function for your own platform, create your own
// implementation file, and place it in a subfolder with named after the OS
// you're targeting. For example, see the Cortex M bare metal version in
// tensorflow/lite/micro/bluepill/micro_time.cc or the mbed one on
// tensorflow/lite/micro/mbed/micro_time.cc.
#include "tensorflow/lite/micro/micro_time.h"
namespace tflite {
// Reference implementation of the ticks_per_second() function that's required
// for a platform to support Tensorflow Lite for Microcontrollers profiling.
// This returns 0 by default because timing is an optional feature that builds
// without errors on platforms that do not need it.
int32_t ticks_per_second() { return 0; }
// Reference implementation of the GetCurrentTimeTicks() function that's
// required for a platform to support Tensorflow Lite for Microcontrollers
// profiling. This returns 0 by default because timing is an optional feature
// that builds without errors on platforms that do not need it.
int32_t GetCurrentTimeTicks() { return 0; }
} // namespace tflite

View File

@ -0,0 +1,31 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_LITE_MICRO_MICRO_TIME_H_
#define TENSORFLOW_LITE_MICRO_MICRO_TIME_H_
#include <stdint.h>
namespace tflite {
// These functions should be implemented by each target platform, and provide an
// accurate tick count along with how many ticks there are per second.
int32_t ticks_per_second();
// Return time in ticks. The meaning of a tick varies per platform.
int32_t GetCurrentTimeTicks();
} // namespace tflite
#endif // TENSORFLOW_LITE_MICRO_MICRO_TIME_H_

View File

@ -0,0 +1,48 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/micro/micro_time.h"
#include "tensorflow/lite/micro/testing/micro_test.h"
TF_LITE_MICRO_TESTS_BEGIN
TF_LITE_MICRO_TEST(TestBasicTimerFunctionality) {
int32_t ticks_per_second = tflite::ticks_per_second();
// Retry enough times to guarantee a tick advance, while not taking too long
// to complete. With 1e6 retries, assuming each loop takes tens of cycles,
// this will retry for less than 10 seconds on a 10MHz platform.
constexpr int kMaxRetries = 1e6;
int start_time = tflite::GetCurrentTimeTicks();
if (ticks_per_second != 0) {
for (int i = 0; i < kMaxRetries; i++) {
if (tflite::GetCurrentTimeTicks() - start_time > 0) {
break;
}
}
}
// Ensure the timer is increasing. This works for the overflow case too, since
// (MIN_INT + x) - (MAX_INT - y) == x + y + 1. For example,
// 0x80000001(min int + 1) - 0x7FFFFFFE(max int - 1) = 0x00000003 == 3.
// GetTicksPerSecond() == 0 means the timer is not implemented on this
// platform.
TF_LITE_MICRO_EXPECT(ticks_per_second == 0 ||
tflite::GetCurrentTimeTicks() - start_time > 0);
}
TF_LITE_MICRO_TESTS_END

View File

@ -0,0 +1,28 @@
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Posix implementation of micro_timer.
// To include this with make, add TAGS=posix.
#include "tensorflow/lite/micro/micro_time.h"
#include <time.h>
namespace tflite {
int32_t ticks_per_second() { return CLOCKS_PER_SEC; }
int32_t GetCurrentTimeTicks() { return clock(); }
} // namespace tflite

View File

@ -0,0 +1,72 @@
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Reference implementation of timer functions. Platforms are not required to
// implement these timer methods, but they are required to enable profiling.
// On platforms that have a POSIX stack or C library, it can be written using
// methods from <sys/time.h> or clock() from <time.h>.
// To add an equivalent function for your own platform, create your own
// implementation file, and place it in a subfolder with named after the OS
// you're targeting. For example, see the Cortex M bare metal version in
// tensorflow/lite/micro/bluepill/micro_timer.cc or the mbed one on
// tensorflow/lite/micro/mbed/micro_timer.cc.
#include "tensorflow/lite/micro/micro_time.h"
// These are headers from Ambiq's Apollo3 SDK.
#include "am_bsp.h" // NOLINT
#include "am_mcu_apollo.h" // NOLINT
#include "am_util.h" // NOLINT
namespace tflite {
namespace {
// Select CTIMER 1 as benchmarking timer on Sparkfun Edge. This timer must not
// be used elsewhere.
constexpr int kTimerNum = 1;
// Clock set to operate at 12MHz.
constexpr int kClocksPerSecond = 12e6;
} // namespace
int32_t ticks_per_second() { return kClocksPerSecond; }
// Calling this method enables a timer that runs for eternity. The user is
// responsible for avoiding trampling on this timer's config, otherwise timing
// measurements may no longer be valid.
int32_t GetCurrentTimeTicks() {
// TODO(b/150808076): Split out initialization, intialize in interpreter.
static bool is_initialized = false;
if (!is_initialized) {
am_hal_ctimer_config_t timer_config;
// Operate as a 32-bit timer.
timer_config.ui32Link = 1;
// Set timer A to continuous mode at 12MHz.
timer_config.ui32TimerAConfig =
AM_HAL_CTIMER_FN_CONTINUOUS | AM_HAL_CTIMER_HFRC_12MHZ;
am_hal_ctimer_stop(kTimerNum, AM_HAL_CTIMER_BOTH);
am_hal_ctimer_clear(kTimerNum, AM_HAL_CTIMER_BOTH);
am_hal_ctimer_config(kTimerNum, &timer_config);
am_hal_ctimer_start(kTimerNum, AM_HAL_CTIMER_TIMERA);
is_initialized = true;
}
return CTIMERn(kTimerNum)->TMR0;
}
} // namespace tflite