processing profiler
This commit is contained in:
8
procprof/do_nothing.py
Normal file
8
procprof/do_nothing.py
Normal file
@ -0,0 +1,8 @@
|
||||
from time import sleep
|
||||
|
||||
|
||||
def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata=None):
|
||||
sleep(0.01)
|
||||
|
||||
|
||||
|
56
procprof/make_example_images.py
Executable file
56
procprof/make_example_images.py
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Dump Example Images")
|
||||
parser.add_argument("-c", "--camera", help="camera channel name", default=None)
|
||||
parser.add_argument("-i", "--input", help="SwissFEL data file", default=None)
|
||||
parser.add_argument("-o", "--output", help="example images as numpy dump", default="example_images.npy")
|
||||
parser.add_argument("-n", "--nimages", help="number of images", type=int, default=1000)
|
||||
|
||||
clargs = parser.parse_args()
|
||||
|
||||
|
||||
import numpy as np
|
||||
from sfdata import SFDataFiles
|
||||
|
||||
|
||||
FPIC = ":FPICTURE"
|
||||
|
||||
|
||||
def main(fn_input, fn_output, camera, nimages)
|
||||
if fn_input is None:
|
||||
imgs = mk_rand(nimages)
|
||||
else:
|
||||
imgs = mk_real(fn_input, camera, nimages)
|
||||
|
||||
print("Writing to:", fn_output)
|
||||
np.save(fn_output, imgs)
|
||||
|
||||
|
||||
def mk_rand(n):
|
||||
print("No input file specified, will write random data")
|
||||
return np.random.random((n, 100, 100))
|
||||
|
||||
|
||||
def mk_real(fn, ch, n):
|
||||
ch = harmonize_channel(ch)
|
||||
with SFDataFiles(fn) as f:
|
||||
imgs = f[ch][:n]
|
||||
nreal = len(imgs)
|
||||
if nreal != n:
|
||||
print(f"Warning: Got only {nreal} images from channel {ch} in {fn}")
|
||||
return imgs
|
||||
|
||||
def harmonize_channel(ch):
|
||||
if not ch.endswith(FPIC):
|
||||
ch += FPIC
|
||||
return ch
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(clargs.input, clargs.output, clargs.camera, clargs.nimages)
|
||||
|
||||
|
||||
|
152
procprof/procprof.py
Executable file
152
procprof/procprof.py
Executable file
@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#fn_proc = "spectrometer.py"
|
||||
#fn_proc = "do_nothing.py"
|
||||
|
||||
#fn_imgs = "example_images.npy"
|
||||
|
||||
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Profile a Processing Script")
|
||||
parser.add_argument("proc", help="processing script")
|
||||
parser.add_argument("imgs", help="example images as numpy dump")
|
||||
|
||||
clargs = parser.parse_args()
|
||||
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
import cProfile as profile
|
||||
import importlib
|
||||
import numpy as np
|
||||
import os
|
||||
import pstats
|
||||
import timeit
|
||||
|
||||
|
||||
PROC_FUNC_NAME = "process_image"
|
||||
|
||||
|
||||
def main(fn_proc, fn_imgs):
|
||||
proc = proc_import(fn_proc)
|
||||
imgs = np.load(fn_imgs)
|
||||
|
||||
pulse_id = timestamp = x_axis = y_axis = None
|
||||
parameters = {
|
||||
"camera_name": "test"
|
||||
}
|
||||
|
||||
def test():
|
||||
for i, img in enumerate(imgs):
|
||||
# print(i)
|
||||
res = proc(
|
||||
img,
|
||||
pulse_id, timestamp, x_axis, y_axis, parameters
|
||||
)
|
||||
|
||||
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
os.makedirs("prof", exist_ok=True)
|
||||
fn_base_res = f"prof/{fn_proc}-{timestamp}"
|
||||
|
||||
func_profile(test, fn_base_res)
|
||||
func_timeit(test, fn_base_res)
|
||||
|
||||
|
||||
# profiling
|
||||
|
||||
def func_profile(func, fn):
|
||||
p = profile.Profile()
|
||||
p.runcall(func)
|
||||
p.print_stats()
|
||||
|
||||
fn_prof = fn + ".prof"
|
||||
p.dump_stats(fn_prof)
|
||||
|
||||
fn_res = fn + ".result"
|
||||
write_stats(p, fn_res)
|
||||
|
||||
|
||||
def write_stats(p, fn):
|
||||
with open(fn, "x") as f:
|
||||
s = pstats.Stats(p, stream=f)
|
||||
s.print_stats()
|
||||
|
||||
|
||||
# timing
|
||||
|
||||
def func_timeit(func, fn, repeat=3, number=1):
|
||||
t = timeit.Timer(func)
|
||||
res = t.repeat(repeat=repeat, number=number)
|
||||
res = np.array(res)
|
||||
res /= number
|
||||
desc = np_describe(res)
|
||||
desc = printable_dict(desc)
|
||||
print(desc)
|
||||
|
||||
fn_res = fn + ".timing"
|
||||
with open(fn_res, "x") as f:
|
||||
f.write(str(res.tolist()))
|
||||
f.write("\n\n")
|
||||
f.write(desc)
|
||||
|
||||
|
||||
def np_describe(a):
|
||||
a = np.asarray(a)
|
||||
aggrs = (
|
||||
min, max,
|
||||
np.median, np.mean,
|
||||
np.var, np.std
|
||||
)
|
||||
return {f.__name__: f(a) for f in aggrs}
|
||||
|
||||
|
||||
def printable_dict(d, header=None):
|
||||
length = maxstrlen(d) + 1
|
||||
lines = ("{}:{}{}".format(k, " "*(length-strlen(k)), v) for k, v in d.items())
|
||||
|
||||
if header:
|
||||
header = format_header(header)
|
||||
lines = [header] + lines
|
||||
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
def maxstrlen(seq):
|
||||
seq = [str(i) for i in seq]
|
||||
return maxlen(seq)
|
||||
|
||||
def maxlen(seq):
|
||||
if not seq: # max of empty sequence is a ValueError
|
||||
return 0
|
||||
return max(len(i) for i in seq)
|
||||
|
||||
def strlen(x):
|
||||
return len(str(x))
|
||||
|
||||
|
||||
# importing
|
||||
|
||||
def proc_import(fn):
|
||||
proc = fn_import(fn)
|
||||
if not hasattr(proc, PROC_FUNC_NAME):
|
||||
msg = f"file \"{fn}\" does not contain processing function: {PROC_FUNC_NAME}"
|
||||
raise ValueError(msg)
|
||||
return proc.process_image
|
||||
|
||||
def fn_import(fn):
|
||||
mod = remove_suffix(fn, ".py")
|
||||
return importlib.import_module(mod)
|
||||
|
||||
def remove_suffix(string, suffix):
|
||||
if string.endswith(suffix):
|
||||
string = string[:-len(suffix)]
|
||||
return string
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(clargs.proc, clargs.imgs)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user