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 package ffx.potential.nonbonded;
39
40 import edu.rit.pj.IntegerSchedule;
41 import edu.rit.util.Range;
42
43
44
45
46
47
48
49 public class SpatialDensitySchedule extends IntegerSchedule {
50
51 private final int[] atomsPerChunk;
52 private final double loadBalancePercentage;
53 private int nThreads;
54 private Range chunkRange;
55 private boolean[] threadDone;
56 private Range[] ranges;
57
58
59
60
61
62
63
64
65
66 SpatialDensitySchedule(
67 int nThreads, int nAtoms, int[] atomsPerChunk, double loadBalancePercentage) {
68 this.atomsPerChunk = atomsPerChunk;
69 this.nThreads = nThreads;
70
71 threadDone = new boolean[nThreads];
72 ranges = new Range[nThreads];
73
74 if (loadBalancePercentage > 0.01 && loadBalancePercentage <= 1.0) {
75 this.loadBalancePercentage = loadBalancePercentage;
76 } else {
77 this.loadBalancePercentage = 1.0;
78 }
79 }
80
81
82
83
84
85
86 @Override
87 public boolean isFixedSchedule() {
88 return true;
89 }
90
91
92 @Override
93 public Range next(int threadID) {
94 if (!threadDone[threadID]) {
95 threadDone[threadID] = true;
96 return ranges[threadID];
97 }
98 return null;
99 }
100
101
102 @Override
103 public void start(int nThreads, Range chunkRange) {
104 this.nThreads = nThreads;
105 this.chunkRange = chunkRange;
106 if (nThreads != threadDone.length) {
107 threadDone = new boolean[nThreads];
108 }
109 for (int i = 0; i < nThreads; i++) {
110 threadDone[i] = false;
111 }
112 if (nThreads != ranges.length) {
113 ranges = new Range[nThreads];
114 }
115
116 defineRanges();
117 }
118
119 private void defineRanges() {
120 int lb = chunkRange.lb();
121 int ub = chunkRange.ub();
122 int thread = 0;
123 int start = 0;
124 int total = 0;
125
126
127 for (int value : atomsPerChunk) {
128 total += value;
129 }
130 int goal = (int) ((total * loadBalancePercentage) / nThreads);
131
132 total = 0;
133 for (int i = lb; i <= ub; i++) {
134 int chunksLeft = ub - i + 1;
135 int threadsLeft = nThreads - thread;
136
137 total += atomsPerChunk[i];
138
139 if (total > goal || chunksLeft <= threadsLeft) {
140 int stop = i;
141
142 Range current = ranges[thread];
143 if (current == null || current.lb() != start || current.ub() != stop) {
144 ranges[thread] = new Range(start, stop);
145 }
146
147
148 thread++;
149 start = i + 1;
150 total = 0;
151
152 if (thread == nThreads - 1) {
153 stop = ub;
154 current = ranges[thread];
155 if (current == null || current.lb() != start || current.ub() != stop) {
156 ranges[thread] = new Range(start, stop);
157 }
158 break;
159 }
160 } else if (i == ub) {
161
162 int stop = i;
163 Range current = ranges[thread];
164 if (current == null || current.lb() != start || current.ub() != stop) {
165 ranges[thread] = new Range(start, stop);
166 }
167 }
168 }
169
170
171 for (int i = thread + 1; i < nThreads; i++) {
172 ranges[i] = null;
173 }
174 }
175 }