taotoolkit 1.1.8__tar.gz → 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taotoolkit
3
- Version: 1.1.8
3
+ Version: 2.0.0
4
4
  Summary: Tao ToolKit
5
5
  Author-email: taotaoli <taotaoli@asrmicro.com>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "taotoolkit"
7
- version = "1.1.8"
7
+ version = "2.0.0"
8
8
  description = "Tao ToolKit"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -39,7 +39,7 @@ from .tao_camDvt import camDvtMain as camDvtMain, printHelp as camDvtHelp, CamDv
39
39
 
40
40
  from .asrVrf import Vrf
41
41
 
42
- __version__ = "1.1.8"
42
+ __version__ = "2.0.0"
43
43
 
44
44
  __all__ = [
45
45
  "debugCtrl",
@@ -20,6 +20,7 @@ from .tao_common import (
20
20
  loge,
21
21
  logi,
22
22
  renameFile,
23
+ sleep,
23
24
  normalize_args,
24
25
  register_command,
25
26
  )
@@ -62,7 +63,7 @@ class CamDvt(asrCamOp):
62
63
  def checkAeChannel(self):
63
64
  cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 3000 r m0_g0 CAECFilter m_pLumaRLong 5 7"
64
65
  try:
65
- out, _ = pCmd(cmd)
66
+ out, _ = pCmd(cmd, sleep_s=1.0)
66
67
  cmdResult = re.split("[ \n,]+", out)[2]
67
68
 
68
69
  if is_number(cmdResult):
@@ -79,7 +80,7 @@ class CamDvt(asrCamOp):
79
80
  """
80
81
 
81
82
  cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 3000 gv"
82
- out, _ = pCmd(cmd)
83
+ out, _ = pCmd(cmd, sleep_s=1.0)
83
84
  if "successfully" in out:
84
85
  timestamp = time.strftime("%Y%m%d_%H%M%S", time.localtime())
85
86
  outPath = os.path.join(os.getcwd(), folderName + timestamp)
@@ -128,7 +129,7 @@ class CamDvt(asrCamOp):
128
129
  total = (gainMax - gainMin) // step + 1
129
130
  for i in range(gainMin, gainMax + 1, step):
130
131
  self.writeIsp("CAECFilter", "m_pTotalGainManual", 0, 0, i)
131
- time.sleep(0.1)
132
+ sleep(0.1)
132
133
  luma = self.readIsp("CAECFilter", "m_pLumaMatrixLong", 5, 7, True)
133
134
  info = "m_pExpTimeManual(us) = %d m_pTotalGainManual(Q8) = %d luma = %f %d/%d" % (
134
135
  ExpTimeManual,
@@ -139,7 +140,7 @@ class CamDvt(asrCamOp):
139
140
  )
140
141
  cur += 1
141
142
  logi(info)
142
- time.sleep(0.1)
143
+ sleep(0.1)
143
144
  self.__filterEnable(1, 1, 1, 1, 1, 1)
144
145
 
145
146
  # debug API
@@ -156,17 +157,17 @@ class CamDvt(asrCamOp):
156
157
  total = (expMax - expMin) // step + 1
157
158
  for i in range(expMin, expMax + 1, step):
158
159
  self.writeIsp("CAECFilter", "m_pExpTimeManual", 0, 0, i)
159
- time.sleep(0.1)
160
+ sleep(0.1)
160
161
  luma = self.readIsp("CAECFilter", "m_pLumaMatrixLong", 5, 7, True)
161
162
 
162
163
  logi(f"m_pExpTimeManual(us) = {i} m_pTotalGainManual(Q8) = {gainManual} luma = {luma} {cur}/{total}")
163
164
  cur += 1
164
- # time.sleep(0.1)
165
+ # sleep(0.1)
165
166
  self.__filterEnable(1, 1, 1, 1, 1, 1)
166
167
 
167
168
  def __getLumaWithGain(self, gain: int):
168
169
  self.writeIsp("CAECFilter", "m_pTotalGainManual", 0, 0, gain)
169
- time.sleep(0.6)
170
+ sleep(0.6)
170
171
  if self.aeChl == 3:
171
172
  r = self.readIsp("CAECFilter", "m_pLumaRLong", 5, 7, True, strict=True)
172
173
  g = self.readIsp("CAECFilter", "m_pLumaGLong", 5, 7, True, strict=True)
@@ -180,7 +181,7 @@ class CamDvt(asrCamOp):
180
181
 
181
182
  def __getLumaWithExp(self, exp: int):
182
183
  self.writeIsp("CAECFilter", "m_pExpTimeManual", 0, 0, exp)
183
- time.sleep(0.6)
184
+ sleep(0.6)
184
185
  if self.aeChl == 3:
185
186
  r = self.readIsp("CAECFilter", "m_pLumaRLong", 5, 7, True, strict=True)
186
187
  g = self.readIsp("CAECFilter", "m_pLumaGLong", 5, 7, True, strict=True)
@@ -208,7 +209,7 @@ class CamDvt(asrCamOp):
208
209
  inVrf,
209
210
  outVrf,
210
211
  )
211
- pCmd(cmd)
212
+ pCmd(cmd, sleep_s=1.0)
212
213
  removeFile(inVrf)
213
214
  vrfObj = asrVrf.Vrf()
214
215
  vrfObj.Read(outVrf)
@@ -286,14 +287,14 @@ class CamDvt(asrCamOp):
286
287
  def __getGainLumaWithVrf(self, gain: int, exp: int):
287
288
  self.writeIsp("CAECFilter", "m_pTotalGainManual", 0, 0, gain)
288
289
  # self.writeIsp("CAECFilter", "m_pExpTimeManual", 0, 0, exp)
289
- time.sleep(0.2)
290
+ sleep(0.2)
290
291
  vrfName = "gain" + str(gain) + "_exp" + str(exp) + ".vrf"
291
292
  return self.getVrfMean(self.outPath, vrfName, True)
292
293
 
293
294
  def __getExpLumaWithVrf(self, gain: int, exp: int):
294
295
  # self.writeIsp("CAECFilter", "m_pTotalGainManual", 0, 0, gain)
295
296
  self.writeIsp("CAECFilter", "m_pExpTimeManual", 0, 0, exp)
296
- time.sleep(0.2)
297
+ sleep(0.2)
297
298
  vrfName = "gain" + str(gain) + "_exp" + str(exp) + ".vrf"
298
299
  return self.getVrfMean(self.outPath, vrfName, True)
299
300
 
@@ -410,7 +411,7 @@ class CamDvt(asrCamOp):
410
411
  f.write(writeStr)
411
412
  logi(writeStr)
412
413
 
413
- time.sleep(1)
414
+ sleep(1)
414
415
 
415
416
  def __aeExpScanVrf(self, blcTest: bool):
416
417
  """
@@ -451,7 +452,7 @@ class CamDvt(asrCamOp):
451
452
  f.write(writeStr)
452
453
  logi(writeStr)
453
454
 
454
- time.sleep(1)
455
+ sleep(1)
455
456
 
456
457
  def __aeGainScanStat(self):
457
458
  """
@@ -504,7 +505,7 @@ class CamDvt(asrCamOp):
504
505
  f.write(writeStr)
505
506
  logi(writeStr.replace("\n", "").replace("\r", ""))
506
507
 
507
- time.sleep(1)
508
+ sleep(1)
508
509
 
509
510
  def __aeExpScanStat(self):
510
511
  """
@@ -557,7 +558,7 @@ class CamDvt(asrCamOp):
557
558
  f.write(writeStr)
558
559
  logi(writeStr.replace("\n", "").replace("\r", ""))
559
560
 
560
- time.sleep(1)
561
+ sleep(1)
561
562
 
562
563
  def calibrateAE(self):
563
564
  m_pExpIndexLong = self.readIsp("CAECFilter", "m_pExpIndexLong", 0, 0, False)
@@ -877,8 +878,8 @@ class CamDvt(asrCamOp):
877
878
  gainMax = self.readIsp("CAECFilter", "m_pMaxAnaGain")
878
879
  print("gainMin(Q8)=", gainMin, "gainMax(Q8)=", gainMax)
879
880
  self.writeIsp("CAECFilter", "m_bManualAEEnable", 0, 0, 1)
880
- pCmd("adb shell rm data/vendor/camera/*", 1)
881
- pCmd("adb shell setprop persist.vendor.camera.enable.capturedump 1", 0.5)
881
+ pCmd("adb shell rm data/vendor/camera/*", sleep_s=1)
882
+ pCmd("adb shell setprop persist.vendor.camera.enable.capturedump 1", sleep_s=0.5)
882
883
  # outPath = os.path.join(self.outPath, "raw")
883
884
  outPath = self.outPath
884
885
  if not os.path.exists(outPath):
@@ -888,12 +889,12 @@ class CamDvt(asrCamOp):
888
889
  print("gain(Q8)=", gain)
889
890
  self.writeIsp("CAECFilter", "m_pTotalGainManual", 0, 0, gain)
890
891
  self.writeIsp("CAECFilter", "m_pAnaGainManual", 0, 0, gain)
891
- time.sleep(0.2)
892
+ sleep(0.2)
892
893
  vrfName = "gain_" + str(gain // 256) + ".vrf"
893
894
  self.dumpVrf(outPath, vrfName)
894
895
  # pCmd("adb shell input keyevent 27",sleep_s=5)
895
896
 
896
- time.sleep(1)
897
+ sleep(1)
897
898
 
898
899
  def gainScanVrf(self):
899
900
  """
@@ -904,8 +905,8 @@ class CamDvt(asrCamOp):
904
905
  gainMax = self.readIsp("CAECFilter", "m_pMaxAnaGain")
905
906
  print("gainMin(Q8)=", gainMin, "gainMax(Q8)=", gainMax)
906
907
  self.writeIsp("CAECFilter", "m_bManualAEEnable", 0, 0, 0)
907
- pCmd("adb shell rm data/vendor/camera/*", 1)
908
- pCmd("adb shell setprop persist.vendor.camera.enable.capturedump 1", 0.5)
908
+ pCmd("adb shell rm data/vendor/camera/*", sleep_s=1)
909
+ pCmd("adb shell setprop persist.vendor.camera.enable.capturedump 1", sleep_s=0.5)
909
910
  # outPath = os.path.join(self.outPath, "raw")
910
911
  outPath = self.outPath
911
912
  if not os.path.exists(outPath):
@@ -917,12 +918,12 @@ class CamDvt(asrCamOp):
917
918
  self.writeIsp("CAECFilter", "m_pMaxAnaGain", 0, 0, gain)
918
919
  self.writeIsp("CAECFilter", "m_pMinTotalGain", 0, 0, gain)
919
920
  self.writeIsp("CAECFilter", "m_pMaxTotalGain", 0, 0, gain)
920
- time.sleep(0.2)
921
+ sleep(0.2)
921
922
  vrfName = "gain_" + str(gain // 256) + ".vrf"
922
923
  self.dumpVrf(outPath, vrfName)
923
924
  # pCmd("adb shell input keyevent 27",sleep_s=5)
924
925
 
925
- time.sleep(1)
926
+ sleep(1)
926
927
 
927
928
  def afScan(self):
928
929
  """
@@ -946,7 +947,7 @@ class CamDvt(asrCamOp):
946
947
  for i in range(startPosition, endPosition + 1, step):
947
948
  self.writeIsp("CAFFilter", "m_nManualMotorPosition", 0, 0, i)
948
949
  self.writeIsp("CAFFilter", "m_bMotorManualTrigger", 0, 0, 1)
949
- time.sleep(1)
950
+ sleep(1)
950
951
  m_pRTFVList = self.readIsp("CAFFilter", "m_pRTFVList", 0, 0, False)
951
952
 
952
953
  writeStr = "%d/%d position = %d FV = %d \n" % (cur, total, i, m_pRTFVList)
@@ -954,11 +955,11 @@ class CamDvt(asrCamOp):
954
955
  f.write(writeStr)
955
956
  logi(writeStr.replace("\n", "").replace("\r", ""))
956
957
 
957
- time.sleep(1)
958
+ sleep(1)
958
959
 
959
960
  def dumpPDVrf(self, outPath: str, posCode: str):
960
961
  cmd = f"{self.tuning_assistant} 127.0.0.1 t 3000 3000 3000 dp m0_g0 {outPath} 1"
961
- out = pCmd(cmd)
962
+ out = pCmd(cmd, sleep_s=1.0)
962
963
 
963
964
  # 使用正则表达式查找关键词之间的字符串
964
965
  keyword1 = "ID="
@@ -999,7 +1000,7 @@ class CamDvt(asrCamOp):
999
1000
  for i in range(startPosition, endPosition + 1, step):
1000
1001
  self.writeIsp("CAFFilter", "m_nManualMotorPosition", 0, 0, i)
1001
1002
  self.writeIsp("CAFFilter", "m_bMotorManualTrigger", 0, 0, 1)
1002
- time.sleep(2)
1003
+ sleep(2)
1003
1004
  # outPath = os.path.join(self.outPath, "raw")
1004
1005
  outPath = self.outPath
1005
1006
  if not os.path.exists(outPath):
@@ -1011,15 +1012,15 @@ class CamDvt(asrCamOp):
1011
1012
  self.dumpVrf(outPath, str(i) + ".vrf")
1012
1013
  logi(f"position = {i} {cur}/{total}")
1013
1014
  cur += 1
1014
- time.sleep(1)
1015
+ sleep(1)
1015
1016
 
1016
1017
  def afDvt(self):
1017
1018
  """
1018
1019
  光源需直流无频闪,照度800lux, 50cm距离细节丰富的chart
1019
1020
  """
1020
1021
 
1021
- pCmd("adb shell input keyevent KEYCODE_HOME", 3)
1022
- pCmd("adb shell am start -a android.media.action.STILL_IMAGE_CAMERA", 2)
1022
+ pCmd("adb shell input keyevent KEYCODE_HOME", sleep_s=3)
1023
+ pCmd("adb shell am start -a android.media.action.STILL_IMAGE_CAMERA", sleep_s=2)
1023
1024
 
1024
1025
  self.__filterEnable(0, 1, 0, 0, 0, 0)
1025
1026
 
@@ -556,7 +556,7 @@ def CLI_videoCut(args=None):
556
556
  v2 = f"lark_scene{scene}"
557
557
  for i in range(5):
558
558
  cmd = f'ffmpeg -i {v1}_{i}.mp4 -i {v2}_{i}.mp4 -filter_complex "[0:v][1:v]hstack=inputs=2" -c:v libx264 -crf 18 -preset slow scene{scene}_{i}.mp4'
559
- oCmd(cmd, showCmd=True, logLevel="info")
559
+ oCmd(cmd, sleep_s=1.0, showCmd=True, logLevel="info")
560
560
 
561
561
 
562
562
  def CLI_video2jpg(argsList):
@@ -569,7 +569,7 @@ def CLI_video2jpg(argsList):
569
569
  os.makedirs(os.path.join(os.path.curdir, args.out), exist_ok=True)
570
570
  cmd = f"ffmpeg -i {args.path} -r {args.fps} -f image2 {args.out}/image-%3d.bmp"
571
571
  logi(f"video2jpg cmd: {cmd}")
572
- oCmd(cmd, showCmd=True, logLevel="info")
572
+ oCmd(cmd, sleep_s=1.0, showCmd=True, logLevel="info")
573
573
 
574
574
 
575
575
  _COMMAND_REGISTRY = {}
@@ -7,6 +7,7 @@ import re
7
7
  import subprocess
8
8
  import sys
9
9
  import time
10
+ import atexit
10
11
  from functools import wraps
11
12
  from datetime import datetime
12
13
  from typing import Callable, Dict, List, Optional, Any
@@ -145,8 +146,64 @@ def iExit(msg: str) -> None:
145
146
  sys.exit(0)
146
147
 
147
148
 
149
+ # ── 命令耗时埋点 ─────────────────────────────────────────
150
+ # 环境变量 TAO_TIMING=1 开启, 进程退出时自动打印汇总;
151
+ # elapsed 只统计命令真实执行时间, sleep_s / 直接 sleep() 单独统计, 便于区分"设备慢"与"等待多"
152
+ _TIMING_ENABLED = os.environ.get("TAO_TIMING", "").strip().lower() not in ("", "0", "false", "off")
153
+ _timingRecords: List[Dict[str, Any]] = []
154
+ _timingSleeps: List[float] = []
155
+
156
+
148
157
  def sleep(seconds: float) -> None:
149
158
  time.sleep(seconds)
159
+ if _TIMING_ENABLED:
160
+ _timingSleeps.append(seconds)
161
+
162
+
163
+ def timingCtrl(enabled: bool) -> None:
164
+ """开关命令耗时埋点"""
165
+ global _TIMING_ENABLED
166
+ _TIMING_ENABLED = enabled
167
+
168
+
169
+ def _timingAdd(kind: str, cmd: str, elapsed: float, sleep_s: float) -> None:
170
+ if _TIMING_ENABLED:
171
+ _timingRecords.append({"kind": kind, "cmd": cmd, "elapsed": elapsed, "sleep": sleep_s})
172
+
173
+
174
+ def timingReport(top=10, reset=False) -> Dict[str, Any]:
175
+ """打印并返回耗时统计: 命令真实耗时、sleep 耗时及占比、最慢的 top 条命令"""
176
+ totalCmd = sum(r["elapsed"] for r in _timingRecords)
177
+ totalSleep = sum(r["sleep"] for r in _timingRecords) + sum(_timingSleeps)
178
+ total = totalCmd + totalSleep
179
+ stat = {
180
+ "count": len(_timingRecords),
181
+ "sleepCalls": len(_timingSleeps),
182
+ "cmdTime": totalCmd,
183
+ "sleepTime": totalSleep,
184
+ "totalTime": total,
185
+ "sleepRatio": (totalSleep / total) if total else 0.0,
186
+ "slowest": sorted(_timingRecords, key=lambda r: r["elapsed"], reverse=True)[:top],
187
+ }
188
+ if _timingRecords or _timingSleeps:
189
+ print(
190
+ f"[timing] 命令数={stat['count']} 直接sleep={stat['sleepCalls']}次 命令耗时={totalCmd:.2f}s "
191
+ f"sleep耗时={totalSleep:.2f}s sleep占比={stat['sleepRatio'] * 100:.1f}%"
192
+ )
193
+ for index, r in enumerate(stat["slowest"], 1):
194
+ print(f"[timing] {index:>2}. {r['elapsed'] * 1000:>8.1f}ms sleep={r['sleep']:.1f}s {r['kind']} {r['cmd'][:100]}")
195
+ if reset:
196
+ _timingRecords.clear()
197
+ _timingSleeps.clear()
198
+ return stat
199
+
200
+
201
+ def _timingAtExit() -> None:
202
+ if _TIMING_ENABLED and (_timingRecords or _timingSleeps):
203
+ timingReport()
204
+
205
+
206
+ atexit.register(_timingAtExit)
150
207
 
151
208
 
152
209
  sysVersion = sys.platform
@@ -326,7 +383,7 @@ def parseDeviceInfo(info: str) -> Dict[str, str]:
326
383
 
327
384
  def pCmd(
328
385
  cmd: str,
329
- sleep_s=1.0,
386
+ sleep_s=0.0, # 默认不等待, 需要等待的调用请显式传 sleep_s
330
387
  showCmd=False,
331
388
  shell=False,
332
389
  splitCmd=True,
@@ -347,6 +404,7 @@ def pCmd(
347
404
  logCallInfo(cmd)
348
405
  else:
349
406
  logCallDebug(cmd)
407
+ t0 = time.perf_counter()
350
408
  try:
351
409
  if splitCmd:
352
410
  proc = subprocess.Popen(
@@ -369,8 +427,10 @@ def pCmd(
369
427
  # env=os.environ.copy(),
370
428
  )
371
429
  except subprocess.TimeoutExpired:
430
+ _timingAdd("pCmd", cmd, time.perf_counter() - t0, 0.0)
372
431
  return "", f"Command '{cmd}' timed out after {timeOut} seconds"
373
432
  except subprocess.CalledProcessError as e:
433
+ _timingAdd("pCmd", cmd, time.perf_counter() - t0, 0.0)
374
434
  return "", f"Command '{cmd}' failed with error: {e.stderr}"
375
435
  out = ""
376
436
  error = ""
@@ -379,12 +439,15 @@ def pCmd(
379
439
  out, error = proc.communicate(timeout=timeOut)
380
440
  except subprocess.TimeoutExpired:
381
441
  logCallErr(f"{cmd} timeout", "error")
442
+ _timingAdd("pCmd", cmd, time.perf_counter() - t0, 0.0)
382
443
  if not ignoreTimeOut:
383
444
  exit()
384
445
  else:
385
446
  return "None", "None"
386
447
 
387
- sleep(sleep_s)
448
+ elapsed = time.perf_counter() - t0
449
+ time.sleep(sleep_s)
450
+ _timingAdd("pCmd", cmd, elapsed, sleep_s)
388
451
  if checkErr:
389
452
  checkMsg(error, "error")
390
453
  checkMsg(out, "failed")
@@ -398,6 +461,8 @@ def pCmd(
398
461
  logCallInfo(error)
399
462
  return out, error
400
463
  else:
464
+ elapsed = time.perf_counter() - t0
465
+ _timingAdd("pCmd", cmd, elapsed, 0.0)
401
466
  return "None", "None"
402
467
 
403
468
 
@@ -449,7 +514,7 @@ def rCmdRealtime(
449
514
 
450
515
  def rCmd(
451
516
  cmd: str,
452
- sleep_s=1.0,
517
+ sleep_s=0.0, # 默认不等待, 需要等待的调用请显式传 sleep_s
453
518
  showCmd=False,
454
519
  shell=False,
455
520
  splitCmd=True,
@@ -468,6 +533,7 @@ def rCmd(
468
533
  logCallInfo(cmd, callStack=3)
469
534
  else:
470
535
  logCallDebug(cmd, callStack=3)
536
+ t0 = time.perf_counter()
471
537
  try:
472
538
  if splitCmd:
473
539
  result = subprocess.run(
@@ -490,11 +556,15 @@ def rCmd(
490
556
  timeout=timeOut,
491
557
  )
492
558
  except subprocess.TimeoutExpired:
559
+ _timingAdd("rCmd", cmd, time.perf_counter() - t0, 0.0)
493
560
  return "", f"Command '{cmd}' timed out after {timeOut} seconds"
494
561
  except subprocess.CalledProcessError as e:
562
+ _timingAdd("rCmd", cmd, time.perf_counter() - t0, 0.0)
495
563
  return "", f"Command '{cmd}' failed with error: {e.stderr}"
496
564
 
497
- sleep(sleep_s)
565
+ elapsed = time.perf_counter() - t0
566
+ time.sleep(sleep_s)
567
+ _timingAdd("rCmd", cmd, elapsed, sleep_s)
498
568
  if checkErr:
499
569
  checkMsg(result.stderr, "error")
500
570
  checkMsg(result.stderr, "failed")
@@ -510,7 +580,8 @@ def rCmd(
510
580
  return result.stdout, result.stderr
511
581
 
512
582
 
513
- def oCmd(cmd: str, sleep_s=1.0, showCmd=False, logLevel="debug"):
583
+ def oCmd(cmd: str, sleep_s=0.0, showCmd=False, logLevel="debug"):
584
+ """执行系统命令; 默认不等待, 需要等待的调用请显式传 sleep_s"""
514
585
  if showCmd:
515
586
  if logLevel == "warn":
516
587
  logCallWarn(cmd, callStack=3)
@@ -520,5 +591,8 @@ def oCmd(cmd: str, sleep_s=1.0, showCmd=False, logLevel="debug"):
520
591
  logCallInfo(cmd, callStack=3)
521
592
  else:
522
593
  logCallDebug(cmd, callStack=3)
594
+ t0 = time.perf_counter()
523
595
  os.system(cmd)
524
- sleep(sleep_s)
596
+ elapsed = time.perf_counter() - t0
597
+ time.sleep(sleep_s)
598
+ _timingAdd("oCmd", cmd, elapsed, sleep_s)