|
1 |
| - |
2 | 1 | ## Comparing the performance of the Julia and MATLAB implementations
|
3 | 2 |
|
4 | 3 | # We can compare the performance of the Julia and MATLAB implementations
|
5 | 4 | # by running the same model for the same number of epochs and measuring
|
6 | 5 | # the time taken.
|
7 | 6 |
|
8 |
| -using BeforeIT, Plots, Statistics |
| 7 | +using BeforeIT, CairoMakie, Statistics, ThreadPinning |
| 8 | + |
| 9 | +pinthreads(:cores) |
9 | 10 |
|
10 | 11 | function run(parameters, initial_conditions, T; multi_threading = false)
|
11 | 12 | model = BeforeIT.init_model(parameters, initial_conditions, T)
|
|
20 | 21 |
|
21 | 22 | parameters = BeforeIT.AUSTRIA2010Q1.parameters
|
22 | 23 | initial_conditions = BeforeIT.AUSTRIA2010Q1.initial_conditions
|
23 |
| -T = 12 |
| 24 | +T = 12 |
24 | 25 |
|
25 | 26 | # We run the code to compile it first
|
26 | 27 | @time run(parameters, initial_conditions, T; multi_threading = false);
|
27 | 28 | @time run(parameters, initial_conditions, T; multi_threading = true);
|
28 | 29 |
|
29 | 30 | # Time taken by the MATLAB code and the Generated C code with MATLAB Coder
|
30 |
| -# (6 threads for the parallel version), computed independently on an AMD Ryzen 5 5600H |
31 |
| -matlab_times = [4.399592, 4.398576, 4.352314, 4.385039, 4.389989] |
32 |
| -matlab_time = mean(matlab_times) |
33 |
| -matlab_time_std = std(matlab_times) |
34 |
| - |
35 |
| -c_times = [0.952, 0.940, 0.951, 0.942, 0.938] |
36 |
| -c_time = mean(c_times) |
37 |
| -c_time_std = std(c_times) |
38 |
| - |
39 |
| -c_times_multi_thread = [0.305, 0.324, 0.330, 0.334, 0.323] |
40 |
| -c_time_multi_thread = mean(c_times_multi_thread) |
41 |
| -c_time_multi_thread_std = std(c_times_multi_thread) |
42 |
| - |
43 |
| -# Time taken by the Julia code (same platform as in the the matlab benchmarks), |
| 31 | +# (4 threads for the parallel version), computed independently on an |
| 32 | +# AMD Ryzen 5 5600H |
| 33 | +matlab_times_small = [4.399592, 4.398576, 4.352314, 4.385039, 4.389989] ./ T |
| 34 | +matlab_times_big = [2000.189556, 1990.485305, 2002.295329, 1994.215843, 1993.651854] |
| 35 | +matlab_mtime_small = mean(matlab_times_small) |
| 36 | +matlab_stime_small = std(matlab_times_small) |
| 37 | +matlab_mtime_big = mean(matlab_times_big) |
| 38 | +matlab_stime_big = std(matlab_times_big) |
| 39 | + |
| 40 | +c_times_small = [0.952, 0.940, 0.951, 0.942, 0.938] ./ T |
| 41 | +c_times_big = [574.692, 576.725, 572.382, 573.921, 575.949] |
| 42 | +c_mtime_small = mean(c_times_small) |
| 43 | +c_stime_small = std(c_times_small) |
| 44 | +c_mtime_big = mean(c_times_big) |
| 45 | +c_stime_big = std(c_times_big) |
| 46 | + |
| 47 | +c_times_small_multi = [0.305, 0.324, 0.330, 0.334, 0.323] ./ T |
| 48 | +c_times_big_multi = [209.603, 210.197, 209.610, 211.759, 209.174] |
| 49 | +c_mtime_small_multi = mean(c_times_small_multi) |
| 50 | +c_stime_small_multi = std(c_times_small_multi) |
| 51 | +c_mtime_big_multi = mean(c_times_big_multi) |
| 52 | +c_stime_big_multi = std(c_times_big_multi) |
| 53 | + |
| 54 | +# timings from "High-performance computing implementations of agent-based |
| 55 | +# economic models for realizing 1: 1 scale simulations of large |
| 56 | +# economies", A. Gill et al. (2021) |
| 57 | +hpc_mtime_big_multi = 22.92 |
| 58 | +hpc_mtime_big = hpc_mtime_big_multi*4 |
| 59 | + |
| 60 | +# Time taken by the Julia code (same platform as in the matlab benchmarks), |
44 | 61 | # computed as the average of 5 runs
|
45 | 62 | n_runs = 5
|
46 | 63 |
|
47 |
| -julia_times_1_thread = zeros(n_runs) |
| 64 | +julia_times_small = zeros(n_runs) |
48 | 65 | for i in 1:n_runs
|
49 |
| - julia_times_1_thread[i] = @elapsed run(parameters, initial_conditions, T; multi_threading = false); |
| 66 | + julia_times_small[i] = @elapsed run(parameters, initial_conditions, T; multi_threading = false); |
50 | 67 | end
|
51 |
| -julia_time_1_thread = mean(julia_times_1_thread) |
52 |
| -julia_time_1_thread_std = std(julia_times_1_thread) |
53 |
| - |
54 |
| -julia_times_multi_thread = zeros(n_runs) |
| 68 | +julia_times_small ./= T |
| 69 | +julia_times_big = [56.593792, 56.297404, 54.682004, 55.079674, 55.192496] |
| 70 | +julia_mtime_small = mean(julia_times_small) |
| 71 | +julia_stime_small = std(julia_times_small) |
| 72 | +julia_mtime_big = mean(julia_times_big) |
| 73 | +julia_stime_big = std(julia_times_big) |
| 74 | + |
| 75 | +julia_times_small_multi = zeros(n_runs) |
55 | 76 | for i in 1:5
|
56 |
| - julia_times_multi_thread[i] = @elapsed run(parameters, initial_conditions, T; multi_threading = true); |
| 77 | + julia_times_small_multi[i] = @elapsed run(parameters, initial_conditions, T; multi_threading = true); |
57 | 78 | end
|
58 |
| -julia_time_multi_thread = mean(julia_times_multi_thread) |
59 |
| -julia_time_multi_thread_std = std(julia_times_multi_thread) |
60 |
| - |
61 |
| -# Get the number of threads used |
62 |
| -n_threads = Threads.nthreads() |
63 |
| - |
64 |
| -theme(:default, bg = :white) |
65 |
| - |
66 |
| -# Bar chart of the time taken vs the time taken by the MATLAB code, also plot the stds as error bars |
67 |
| -bar( |
68 |
| - ["MATLAB", "Gen. C, 1 thread", "Gen. C, 6 threads", "Julia, 1 thread", "Julia, $n_threads threads"], |
69 |
| - [matlab_time, c_time, c_time_multi_thread, julia_time_1_thread, julia_time_multi_thread], |
70 |
| - yerr = [matlab_time_std, c_time_std, c_time_multi_thread_std, julia_time_1_thread_std, julia_time_multi_thread_std], |
71 |
| - legend = false, |
72 |
| - dpi = 300, |
73 |
| - size = (400, 300), |
74 |
| - grid = false, |
75 |
| - ylabel = "Time for one simulation (s)", |
76 |
| - xtickfont = font(4), |
77 |
| - ytickfont = font(6), |
78 |
| - guidefont = font(6) |
79 |
| -) |
80 |
| - |
81 |
| -# Save the image |
82 |
| -savefig("benchmark_w_matlab.png") |
83 |
| - |
84 |
| -# The Julia implementation is faster than the MATLAB implementation, and the multi-threaded version is |
85 |
| -# faster than the single-threaded version. |
| 79 | +julia_times_small_multi ./= T |
| 80 | +julia_times_big_multi = [35.775353, 34.933283, 35.594063, 35.469412, 35.521846] |
| 81 | +julia_mtime_small_multi = mean(julia_times_small_multi) |
| 82 | +julia_stime_small_multi = std(julia_times_small_multi) |
| 83 | +julia_mtime_big_multi = mean(julia_times_big_multi) |
| 84 | +julia_stime_big_multi = std(julia_times_big_multi) |
| 85 | + |
| 86 | + |
| 87 | +labels = ["MATLAB", "Gen. C, 1 core", "Gen. C, 4 cores", "HPC, 1 core*", "HPC, 4 cores*", |
| 88 | + "BeforeIT.jl, 1 core", "BeforeIT.jl, 4 cores"] |
| 89 | + |
| 90 | +# Create the layout |
| 91 | +fig = Figure(size = (800, 400)); |
| 92 | + |
| 93 | +ax1 = Axis(fig[1, 1], ylabel="time for one epoch (s)", title="Model with 8 thousands agents") |
| 94 | +ax2 = Axis(fig[1, 2], title="Model with 8 millions agents") |
| 95 | + |
| 96 | +times_small = [matlab_mtime_small, c_mtime_small, c_mtime_small_multi, julia_mtime_small, julia_mtime_small_multi] |
| 97 | +barplot!(ax1, |
| 98 | + 1:5, |
| 99 | + times_small, |
| 100 | + bar_labels = :y, |
| 101 | +); |
| 102 | +ylims!(ax1, 0, 1.15*maximum(times_small)) |
| 103 | + |
| 104 | +ax1.yticklabelspace = 25.0 |
| 105 | +ax1.xticks = (1:5, [labels[1:3]..., labels[6:end]...]) |
| 106 | +ax1.xticklabelrotation = 45.0 |
| 107 | +ax1.xgridvisible = false |
| 108 | + |
| 109 | +times_big = [matlab_mtime_big, c_mtime_big, c_mtime_big_multi, hpc_mtime_big, hpc_mtime_big_multi, |
| 110 | + julia_mtime_big, julia_mtime_big_multi] |
| 111 | + |
| 112 | +ylims!(ax2, 0, 1.15*maximum(times_big)) |
| 113 | +barplot!(ax2, |
| 114 | + 1:7, |
| 115 | + round.(times_big, digits=1), |
| 116 | + bar_labels = :y |
| 117 | +); |
| 118 | +ax2.xticks = (1:7, labels) |
| 119 | +ax2.xticklabelrotation = 45.0 |
| 120 | +ax2.xgridvisible = false |
| 121 | + |
| 122 | +# Save or display the layout |
| 123 | +display(fig) |
| 124 | + |
| 125 | +save("benchmark_w_matlab.png", fig) |
0 commit comments