前言
在優(yōu)化c#代碼或?qū)Ρ饶承゛pi的效率時,通常需要測試某個方法的運行時間,可以通過datetime來統(tǒng)計指定方法的執(zhí)行時間,也可以使用命名空間system.diagnostics
中封裝了高精度計時器queryperformancecounter方法的stopwatch類來統(tǒng)計指定方法的執(zhí)行時間:
1.使用datetime方法:
1
2
3
4
5
|
datetime datetime = datetime.now; myfunc(); console.writeline((datetime.now - datetime).totalmilliseconds); |
2.使用stopwatch方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
stopwatch stopwatch = new stopwatch(); stopwatch.start(); myfunc(); stopwatch.stop(); console.writeline(stopwatch.elapsedmilliseconds); //本次myfunc()方法的運行毫秒數(shù) //重置計時器 stopwatch.restart(); //此處可以使用stopwatch.reset(); stopwatch.start();組合代替 myfunc(); stopwatch.stop(); console.writeline(stopwatch.elapsedmilliseconds); //本次myfunc()方法的運行毫秒數(shù) |
以上兩種辦法都可以達到獲取方法執(zhí)行時間的目的,但是在需要對整個項目中的方法都進行監(jiān)測用時時,除了使用性能分析工具,我們還可以通過代碼注入的方式給程序集中每一個方法加入計時器;
通過命名空間system.reflection.emit
中的類可以動態(tài)的創(chuàng)建程序集、類型和成員,通常類庫mono.cecil
可以動態(tài)讀取并修改已經(jīng)生成的il文件,這種在不修改源代碼的情況下給程序集動態(tài)添加功能的技術(shù)稱為面向切面編程(aop);
這里給出了一個注入使用stopwatch來檢測方法執(zhí)行時間的代碼,這里的mono.cecil
類庫可以通過nuget進行安裝:
1
2
3
4
5
6
7
|
using system; using system.io; using system.linq; using system.diagnostics; using mono.cecil; using mono.cecil.cil; using mono.collections.generic; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
static void main( string [] args) { for ( int i = 0; i < args.length; i++) { filestream filestream = new filestream(args[i], filemode.open); if (filestream != null ) { assemblydefinition ad = assemblydefinition.readassembly(filestream); moduledefinition md = ad.mainmodule; collection<typedefinition> typedefinition = md.types; foreach (typedefinition type in typedefinition) { if (type.isclass) { foreach (methoddefinition method in type.methods) { if (method.ispublic && !method.isconstructor) { ilprocessor il = method.body.getilprocessor(); typereference stt = md.importreference( typeof (stopwatch)); variabledefinition stv = new variabledefinition(stt); method.body.variables.add(stv); instruction first = method.body.instructions.first(); il.insertbefore(first, il.create(opcodes.newobj, md.importreference( typeof (stopwatch).getconstructor( new type[] { })))); il.insertbefore(first, il.create(opcodes.stloc_s, stv)); il.insertbefore(first, il.create(opcodes.ldloc_s, stv)); il.insertbefore(first, il.create(opcodes.callvirt, md.importreference( typeof (stopwatch).getmethod( "start" )))); instruction @ return = method.body.instructions.last(); il.insertbefore(@ return , il.create(opcodes.ldloc_s, stv)); il.insertbefore(@ return , il.create(opcodes.callvirt, md.importreference( typeof (stopwatch).getmethod( "stop" )))); il.insertbefore(@ return , il.create(opcodes.ldstr, $ "{method.fullname} run time: " )); il.insertbefore(@ return , il.create(opcodes.ldloc_s, stv)); il.insertbefore(@ return , il.create(opcodes.callvirt, md.importreference( typeof (stopwatch).getmethod( "get_elapsedmilliseconds" )))); il.insertbefore(@ return , il.create(opcodes.box, md.importreference( typeof ( long )))); il.insertbefore(@ return , il.create(opcodes.call, md.importreference( typeof ( string ).getmethod( "concat" , new type[] { typeof ( object ), typeof ( object ) })))); il.insertbefore(@ return , il.create(opcodes.call, md.importreference( typeof (console).getmethod( "writeline" , new type[] { typeof ( string ) })))); } } } } fileinfo fileinfo = new fileinfo(args[i]); string filename = fileinfo.name; int pointindex = filename.lastindexof( '.' ); string frontname = filename.substring(0, pointindex); string backname = filename.substring(pointindex, filename.length - pointindex); string writefilepath = path.combine(fileinfo.directory.fullname, frontname + "_inject" + backname); ad.write(writefilepath); console.writeline($ "success! output path: {writefilepath}" ); filestream.dispose(); } } console.read(); } |
完整的項目傳到了github上=>injectionstopwatchcode,下載項目后,通過dotnet build
命令即可編譯出可執(zhí)行程序,將目標(biāo)程序集文件拖入到該應(yīng)用程序即可在程序集目錄導(dǎo)出注入代碼后的程序集文件,經(jīng)過測試,包括方法擁有返回值和方法的參數(shù)列表中包含out和ref參數(shù)等情況都不會對運行結(jié)果產(chǎn)生影響;
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
using system; public class myclass { public void myfunc() { int num = 1; for ( int i = 0; i < int .maxvalue; i++) { num++; } } } public class program { public static void main( string [] args) { myclass myobj = new myclass(); myobj.myfunc(); console.read(); } } |
原始il代碼:
代碼注入后il代碼:
代碼注入后運行結(jié)果:
總結(jié):
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。
原文鏈接:https://www.cnblogs.com/minotauros/p/9930163.html