Про micros() или странная оптимизация
- Войдите на сайт для отправки комментариев
Доброй субботы, аксакалы!
Пока даже примерно не могу сообразить, растут ли ноги вопроса в аппаратных есебенностях ESP, особенностях оптимизации IDE или моей необразованности, поэтому - в песочнице.
Набросал вспомогательную функцию для формирования имен файлов для даталоггера на SD. Краткое содержание функции: получает адрес частично сформированного шаблона и вставляет в нужные места дату и id исполнительного устройства: 0ID_ММДД.ext
Для ускорения работы добавлены условные варианты. В легких случайх обходимся простым присваиванием сонстанты. В неочевидных - немного математики. То есть, например id = 5 (005) должен подставляться быстрее скажем 241.
В общем, дальше просто выложу листинг с результатами.
// ESP32 devkit v1 4mB // v.1.8.13 // ESP core v 1.0.4 void setup() { Serial.begin(115200); Serial.println('\n'); Serial.println("Из setup: "); char filename[13] = "***_****.day" ; delay(1000); Serial.print("fName, mks: "); uint32_t mks = micros(); fName1(filename, 123, 12, 31); Serial.println(micros() - mks); Serial.println(filename); Serial.print("fName, mks: "); mks = micros(); fName1(filename, 1, 2, 3); Serial.println(micros() - mks); Serial.println(filename); Serial.print("fName, mks: "); mks = micros(); fName1(filename, 123, 12, 31); Serial.println(micros() - mks); Serial.println(filename); Serial.println('\n'); Serial.println("Из функции: "); // Те же действия, перепакованные в функцию bla(1, 1, 1); bla(10, 1, 1); bla(123, 1, 1); bla(1, 10, 1); bla(1, 1, 10); bla(123, 12, 31); } void bla(uint8_t id, uint8_t m, uint8_t d){ char filename[13] = "***_****.day" ; Serial.print("fName, mks: "); uint32_t mks = micros(); fName1(filename, id, m, d); Serial.println(micros() - mks); Serial.println(filename); } /* * char filename[13] = "0ID_MMDD.ext" (8.3); * fName(filename,relay_id, mon, day, ); */ void fName1(char * ch, uint8_t id, uint8_t mon, uint8_t day){ // 11-20 mks if (id > 99) *ch = (char)(floor(id/100)+48); else *ch = '0'; if (id > 9) *(ch+1) = (char)(floor((id%100)/10)+48); else *(ch+1) = '0'; if (id > 9) *(ch+2) = (char)((id%10)+48); else *(ch+2) = (char)(id + 48); if (mon>9) {*(ch+4) = '1'; *(ch+5) = (char)(mon + 38);} else {*(ch+4) = '0'; *(ch+5) = (char)(mon + 48);} if (day>9) { uint8_t d1 = floor(day/10); *(ch+6) = (char)(d1 + 48); *(ch+7) = (char)(day - (d1*10) + 48);} else {*(ch+6) = '0'; *(ch+7) = (char)(day + 48);} } void loop() {}
Результат работы:
Собственно вопросы вызывают странные результаты micros():
Первый вызов функции fName() происходит существенно дольше всех последующих. Я даже там делэй(1000) добавил, чтобы ЕСПшка все свои стартовые дела успела доделать, хотя понимаю, что это фигня.
Следующие вызовы из setup хоть и подозрительно короткие, но логично отличаются по времени выполнения.
С вызовами из промежуточной функции вообще логики мало. Такое ощущение, что там микрос от балды лепится.
Подозрений несколько:
1. особенности реализации micros() при первом вызове.
2. Хитрый компилятор шельмует с повторным вызовом fName, хотя я не понимаю КАК.
Подскажите, куда рыть. Вопрос не принципиальный, просто хочу все знать))
А где вопрос то?
Блин, да Вы троллите нас!
Блин, да Вы троллите нас!
Евгений Петрович, и в мыслях не было. Вот туплю где-то жестко, это да. Вот только никак понять не могу где
А где вопрос то?
Вопрос простой. Почему такая разница в показаниях при выполнении одного кода. Точнее, вопрос в том, где я туплю
Вот только никак понять не могу где
floor - это функция для плавающей точки. Целочисленное деление И ТАК выполняется с отбрасыванием остатка. Вы же зачем-то вызываете floor для результата целочисленного деления, т.е. преобразуете аргумент к float, берёте целую часть, и преобразуете обратно к целому. При этом, при первом вызове, инициализируете библиотеку плавающей точки.
Но, это не всё. Чего Вы навертели в функции fName1? Нафига такие сложности-то? Показать Вам как она пишется?
Вот только никак понять не могу где
floor - это функция для плавающей точки. Целочисленное деление И ТАК выполняется с отбрасыванием остатка. Вы же зачем-то вызываете floor для результата целочисленного деления, т.е. преобразуете аргумент к float, берёте целую часть, и преобразуете обратно к целому. При этом, при первом вызове, инициализируете библиотеку плавающей точки.
Но, это не всё. Чего Вы навертели в функции fName1? Нафига такие сложности-то? Показать Вам как она пишется?
Про округление целочисленных вниз я если и знал, то забыл. В этом себе всю боль о организовал. За науку признателен. Все вопросы отпали. Теперь сам все сделаю, это же элементарно. Но Ваш пример хотел бы увидеть. Не для того, чтобы скопипастить, это не мой путь. Для знакомства с лучшими практиками
ЗЫ: пожалуй, выпью сегодня после баньки за ваше здоровье бокал эсторского))
Всё понимаю - но нахера - не понимаю.
А если электричество выключат? Или кошка-мышка хвостом махнёт?
Всё понимаю - но нахера - не понимаю.
А если электричество выключат? Или кошка-мышка хвостом махнёт?
Не в то окно, да? :)
Ну, вот, смотрите, Вы пишете(я убрал floor)
Но ведь, если id < 99, то частное от деления id/100 будет равен 0. Не проще ли написать
Да, этот вариант хуже тем, что деление выполняется всегда, а в Вашем случае только когда надо. Но такая экономия имела бы смысл, если бы это было в цикле с миллионом проходов. А так ... вы экономите копейки, зато усложняете программу (а усложнение - это удобрение почвы на которой баги растут).
Я бы сделал отдельную функцию, которая преобразует одно число, и вызывал бы её три раза. Примерно, так:
Ну, вот, смотрите, Вы пишете(я убрал floor)
Но ведь, если id < 99, то частное от деления id/100 будет равен 0. Не проще ли написать
Да, этот вариант хуже тем, что деление выполняется всегда, а в Вашем случае только когда надо. Но такая экономия имела бы смысл, если бы это было в цикле с миллионом проходов. А так ... вы экономите копейки, зато усложняете программу (а усложнение - это удобрение почвы на которой баги растут).
Вот не зря тему создал. Сейчас кажется, что это элементарное решение, но сам бы до этого в текущем году не дошел бы. После того, как функция стала укладываться в 1 мкс затратами процессорного времени на выполнение деления готов пренебречь)) Еще раз спасибо!