1 // Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <stdlib.h>
16 #include "xtensa_perfmon_apis.h"
17 #include "xtensa_perfmon_masks.h"
18
19 static const char *TAG = "perfmon";
20
xtensa_perfmon_exec(const xtensa_perfmon_config_t * config)21 esp_err_t xtensa_perfmon_exec(const xtensa_perfmon_config_t *config)
22 {
23 esp_err_t result = ESP_OK;
24 if (config->call_function == NULL) {
25 ESP_LOGE(TAG, "Parameter call_function must be defined.");
26 return ESP_ERR_INVALID_ARG;
27 }
28 if (config->callback == NULL) {
29 ESP_LOGE(TAG, "Parameter callback must be defined.");
30 return ESP_ERR_INVALID_ARG;
31 }
32 for (size_t n = 0; n < config->counters_size; n++) {
33 uint32_t call_min = UINT32_MAX;
34 uint32_t call_max = 0;
35 float result_value = 0;
36
37 for (size_t i = 0; i < config->repeat_count; i++) {
38 // Set up cycle counter
39 xtensa_perfmon_stop();
40 int kernelcnt = 0;
41 // if tracelevel used, then kernelcnt will be enabled
42 if (config->tracelevel >=0) kernelcnt = 1;
43 xtensa_perfmon_init(0, 0, 0xffff, kernelcnt, config->tracelevel);
44 xtensa_perfmon_init(1, config->select_mask[n * 2 + 0], config->select_mask[n * 2 + 1], kernelcnt, config->tracelevel);
45 xtensa_perfmon_start();
46 config->call_function(config->call_params);
47 xtensa_perfmon_stop();
48 uint32_t p0 = xtensa_perfmon_value(0);
49 uint32_t p1 = xtensa_perfmon_value(1);
50 result_value += (float)p1 / config->repeat_count;
51 if (p0 < call_min) {
52 call_min = p0;
53 }
54 if (p0 > call_max) {
55 call_max = p0;
56 }
57 ESP_LOGV(TAG, "p0 = %i, p1 = %i", p0, p1);
58 }
59 uint32_t call_diff = (call_max - call_min);
60
61 if (call_diff > call_max * config->max_deviation) {
62 return ESP_FAIL;
63 } else {
64 config->callback(config->callback_params, config->select_mask[n * 2 + 0], config->select_mask[n * 2 + 1], (uint32_t)result_value);
65 }
66 }
67 return result;
68 }
69
xtensa_perfmon_view_cb(void * params,uint32_t select,uint32_t mask,uint32_t value)70 void xtensa_perfmon_view_cb(void *params, uint32_t select, uint32_t mask, uint32_t value)
71 {
72 FILE *handle;
73 if (params != NULL) {
74 handle = (FILE *)params;
75 } else {
76 handle = stdout;
77 }
78 for (int i = 0 ; xtensa_perfmon_select_table[i].select != -1; i++) {
79 if (xtensa_perfmon_select_table[i].select == select) {
80 fprintf(handle, "Value = %9i, select = %2i, mask = %04x. %s.\n", value, select, mask, xtensa_perfmon_select_table[i].description);
81 }
82 }
83 for (int i = 0 ; xtensa_perfmon_masks_table[i].select != -1; i++) {
84 if ((xtensa_perfmon_masks_table[i].select == select) && (xtensa_perfmon_masks_table[i].mask & mask)) {
85 fprintf(handle, " %s\n", xtensa_perfmon_masks_table[i].description);
86 }
87 }
88 }
89