Skip to content

Commit 102ff18

Browse files
committed
sys.device: 100x speedup on Windows
1 parent 5ec68d5 commit 102ff18

File tree

6 files changed

+96
-17
lines changed

6 files changed

+96
-17
lines changed

+stdlib/+sys/device.m

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@
99

1010
function [i, cmd] = device(p)
1111

12-
i = uint64([]);
13-
if ~stdlib.exists(p), return, end
12+
i = [];
1413

1514
if ispc()
16-
c0 = 'pwsh -c "(Get-CimInstance -ClassName Win32_Volume -Filter \"DriveLetter = ''';
17-
c1 = stdlib.root_name(stdlib.absolute(p));
18-
c2 = '''\").SerialNumber"';
19-
% needs to be strcat as it could be char, or cast implicitly to string
20-
cmd = strcat(c0, c1, c2);
15+
rn = stdlib.root_name(stdlib.absolute(p));
16+
17+
% Get-CimInstance works, but is 100x slower
18+
% c0 = 'pwsh -c "(Get-CimInstance -ClassName Win32_Volume -Filter \"DriveLetter = ''';
19+
% c2 = '''\").SerialNumber"';
20+
% cmd = strcat(c0, rn, c2);
21+
22+
cmd = sprintf('vol "%s"', rn);
2123
elseif ismac()
2224
cmd = sprintf('stat -f %%d "%s"', p);
2325
else
@@ -27,7 +29,13 @@
2729
if stdlib.exists(p)
2830
[s, m] = system(cmd);
2931
if s == 0
30-
i = str2double(m);
32+
if ispc()
33+
r = extractAfter(m, 'Volume Serial Number is ');
34+
r = [r(1:4) r(6:9)];
35+
i = hex2dec(r);
36+
else
37+
i = str2double(m);
38+
end
3139
end
3240
end
3341

+stdlib/device.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
function [i, b] = device(file, backend)
1010
arguments
11-
file
12-
backend (1,:) string = ["java", "perl", "python", "sys"]
11+
file string
12+
backend (1,:) string = ["java", "python", "perl", "sys"]
1313
end
1414

1515
o = stdlib.Backend(mfilename(), backend);

example/BenchmarkDevice.m

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
classdef (SharedTestFixtures={ matlab.unittest.fixtures.PathFixture("..")}) ...
2+
BenchmarkDevice < matlab.perftest.TestCase
3+
4+
properties
5+
exist = "."
6+
not_exist = tempname()
7+
fun = @stdlib.device
8+
end
9+
10+
properties(TestParameter)
11+
backend
12+
end
13+
14+
methods (TestParameterDefinition, Static)
15+
function backend = setupBackend()
16+
backend = init_backend('device');
17+
end
18+
end
19+
20+
21+
methods (Test)
22+
23+
function bench_exist(tc, backend)
24+
tc.startMeasuring()
25+
i = tc.fun(tc.exist, backend);
26+
tc.stopMeasuring()
27+
28+
tc.verifyClass(i, 'uint64')
29+
tc.assertNotEmpty(i)
30+
tc.verifyGreaterThan(i, 0)
31+
end
32+
33+
34+
function bench_not_exist(tc, backend)
35+
tc.startMeasuring()
36+
i = tc.fun(tc.not_exist, backend);
37+
tc.stopMeasuring()
38+
39+
tc.verifyClass(i, 'uint64')
40+
tc.verifyEmpty(i)
41+
end
42+
43+
end
44+
45+
end

example/BenchmarkDeviceRun.m

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
function [r, s] = BenchmarkDeviceRun()
2+
tname = "BenchmarkDevice";
3+
4+
%% Exist
5+
r.same = run_bench(tname + "/bench_exist");
6+
s.exist = sampleSummary(r.same);
7+
disp(sortrows(s.exist, "Median"))
8+
%% Not Exist
9+
r.not = run_bench(tname + "/bench_not_exist");
10+
s.not = sampleSummary(r.not);
11+
disp(sortrows(s.not, "Median"))
12+
13+
end
14+
15+
16+
function result = run_bench(name)
17+
suite = testsuite(name);
18+
exp = matlab.perftest.TimeExperiment.limitingSamplingError(MaxSamples=20, RelativeMarginOfError=0.1);
19+
result = exp.run(suite);
20+
end

example/BenchmarkInode.m

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
classdef (SharedTestFixtures={ matlab.unittest.fixtures.PathFixture("..")}) ...
22
BenchmarkInode < matlab.perftest.TestCase
33

4+
properties
5+
exist = mfilename('fullpath') + ".m"
6+
not_exist = tempname()
7+
fun = @stdlib.inode
8+
end
9+
410
properties(TestParameter)
511
backend
612
end
@@ -15,9 +21,8 @@
1521
methods (Test)
1622

1723
function bench_exist(tc, backend)
18-
file = mfilename('fullpath') + ".m";
1924
tc.startMeasuring()
20-
i = stdlib.inode(file, backend);
25+
i = tc.fun(tc.exist, backend);
2126
tc.stopMeasuring()
2227

2328
tc.verifyClass(i, 'uint64')
@@ -27,9 +32,8 @@ function bench_exist(tc, backend)
2732

2833

2934
function bench_not_exist(tc, backend)
30-
file = tempname();
3135
tc.startMeasuring()
32-
i = stdlib.inode(file, backend);
36+
i = tc.fun(tc.not_exist, backend);
3337
tc.stopMeasuring()
3438

3539
tc.verifyClass(i, 'uint64')

example/BenchmarkInodeRun.m

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
function [r, s] = BenchmarkInodeRun()
2+
tname = "BenchmarkInode";
3+
24
%% Exist
3-
r.same = run_bench('BenchmarkInode/bench_exist');
5+
r.same = run_bench(tname + "/bench_exist");
46
s.exist = sampleSummary(r.same);
57
disp(sortrows(s.exist, "Median"))
68
%% Not Exist
7-
r.not = run_bench('BenchmarkInode/bench_not_exist');
9+
r.not = run_bench(tname + "/bench_not_exist");
810
s.not = sampleSummary(r.not);
911
disp(sortrows(s.not, "Median"))
1012

@@ -13,6 +15,6 @@
1315

1416
function result = run_bench(name)
1517
suite = testsuite(name);
16-
exp = matlab.perftest.TimeExperiment.limitingSamplingError(MaxSamples=25, RelativeMarginOfError=0.1);
18+
exp = matlab.perftest.TimeExperiment.limitingSamplingError(MaxSamples=20, RelativeMarginOfError=0.1);
1719
result = exp.run(suite);
1820
end

0 commit comments

Comments
 (0)