summaryrefslogtreecommitdiff
path: root/tests/utils/gparmake.pp
blob: b4ce34e3e0435348731179a38b40b0b2d7bde1e9 (plain)
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
{ See procedure "Usage". This code is in the public domain. }

Program GParMake;

Uses
  Classes;

procedure Usage;
  begin
    writeln('GParMake: create make rules for parallel execution of testsuite');
    writeln('Usage: gparmake [-a] <outputfile> <dirname> <startchunk> <tests_per_chunk> <test1> [<test2> ...]');
    writeln('Output: makefile fragment with rules to run the tests in sequences of <tests_per_chunk>');
    writeln;
    halt(1);
  end;

{ make all numbers of the same string length so they can be sorted
  lexographically }
function rulenr2str(rulenr: longint): string;
  var
    i: longint;
  begin
    str(rulenr:9,rulenr2str);
    for i:=1 to length(rulenr2str)-1 do
      if rulenr2str[i]=' ' then
        rulenr2str[i]:='0';
  end;

procedure WriteChunkRule(rulenr: longint; const dirname, files: ansistring);
  var
    rulestr: string;
  begin
    rulestr:=rulenr2str(rulenr)+dirname;
    writeln('$(TEST_OUTPUTDIR)/testchunk_',rulestr,'-stamp.$(TEST_FULL_TARGET): testprep-stamp.$(TEST_FULL_TARGET)');
    writeln(#9'$(Q)$(DOTEST) $(DOTESTOPT) -Lchunk',rulestr,' -e ',files);
    writeln(#9'$(ECHOREDIR) $(TEST_DATETIME) > $@');
    writeln;
    writeln('$(addsuffix .chunk',rulestr,', $(LOGFILES)) : $(TEST_OUTPUTDIR)/testchunk_',rulestr,'-stamp.$(TEST_FULL_TARGET)');
    writeln;
    writeln('.INTERMEDIATE: $(addsuffix .chunk',rulestr,', $(LOGFILES)) $(TEST_OUTPUTDIR)/testchunk_',rulestr,'-stamp.$(TEST_FULL_TARGET)');
    writeln;
  end;


var
  startchunk: longint;
  dirname : ansistring;
  doappend: boolean;
  FileList : TStringList;

Function ProcessArgs: longint;
  var
    i,
    paramnr,
    chunktargetsize,
    chunksize,
    chunknr,
    nextfileindex,
    error: longint;
    testname,
    nexttestname,
    testlist,
    s,
    outputname: ansistring;
    filelist : array of ansistring;
    responsefile : text;

  procedure AddFile(const s : ansistring);
    begin
      if nextfileindex>high(filelist) then
        SetLength(filelist,length(filelist)+128);
      filelist[nextfileindex]:=s;
      inc(nextfileindex);
    end;

  procedure FlushChunk;
    begin
      WriteChunkRule(chunknr,dirname,testlist);
      inc(chunknr);
      testlist:='';
      chunksize:=0;
    end;

  begin
    if paramcount < 3 then
      Usage;

    doappend:=false;

    paramnr:=1;
    if paramstr(paramnr)='-a' then
      begin
        doappend:=true;
        inc(paramnr);
      end;

    outputname:=paramstr(paramnr);
    inc(paramnr);

    dirname:=paramstr(paramnr);
    inc(paramnr);

    val(paramstr(paramnr),startchunk,error);
    if error<>0 then
      Usage;
    inc(paramnr);

    val(paramstr(paramnr),chunktargetsize,error);
    if error<>0 then
      Usage;
    inc(paramnr);

    { only redirect output after all possible cases where we may have to write
      the usage screen }
    assign(output,outputname);
    if doappend then
      append(output)
    else
      rewrite(output);

    chunknr:=startchunk;
    chunksize:=0;
    testlist:='';
    nextfileindex:=0;
    for i := paramnr to paramcount do
      begin
        if paramstr(i)[1]='@' then
          begin
            assign(responsefile,copy(paramstr(i),2,length(paramstr(i))));
            reset(responsefile);
            while not(eof(responsefile)) do
              begin
                readln(responsefile,s);
                { Avoid problem with GNU make version 4
                  which adds lines containing
                  make[X] Entering/leaving ... }
                if not (copy(s,1,5)='make[') then
                  AddFile(s);
              end;
            close(responsefile);
          end
        else
          AddFile(paramstr(i));
      end;

    for i := 0 to nextfileindex-1 do
      begin
        testname:=filelist[i];
        testlist:=testlist+' '+testname;
        inc(chunksize);
        if chunksize>=chunktargetsize then
          begin
            if (i=nextfileindex-1) then
              FlushChunk
            else
              begin
                { keep tests with the same name except for the last character in the same chunk,
                  because they may have to be executed in order (skip ".pp" suffix and last char) }
                if i+1>=nextfileindex then
                  nexttestname:=''
                else
                  nexttestname:=filelist[i+1];
                if lowercase(copy(testname,1,length(testname)-4))<>lowercase(copy(nexttestname,1,length(nexttestname)-4)) then
                  FlushChunk;
              end;
          end;
      end;
    if chunksize<>0 then
      FlushChunk;
    ProcessArgs:=chunknr-1;
  end;


procedure WriteWrapperRules(totalchunks: longint);
  const
    lognames: array[1..3] of string[11] = ('log','faillist','longlog');
  var
    logi,
    i: longint;
  begin
    for logi:=1 to 3 do
      begin
        write('$(TEST_OUTPUTDIR)/',lognames[logi],' :');
        for i:=startchunk to totalchunks do
          write(' $(TEST_OUTPUTDIR)/',lognames[logi],'.chunk',rulenr2str(i)+dirname);
        writeln;
        { if you have multiple rules for one (non-pattern) target, all
          prerequisites will be merged, but only one of the rules can have a
          recipe }
        if not doappend then
          begin
            writeln(#9'$(Q)$(CONCAT) $(sort $^) $@');
            writeln;
          end;
        writeln;
      end;
    if not doappend then
      begin
        writeln('gparmake_allexectests : $(LOGFILES)');
        writeln;
      end;
  end;


var
  totalchunks: longint;
begin
  totalchunks:=ProcessArgs;
  WriteWrapperRules(totalchunks);
  close(output);
end.