## 3 Concepts and Methods
### Callgraph Division
#### 3.1.2 Subgraph Merging  
Since the number of subgraphs divided from the callgraph by [PERSON] algorithm far exceeds the number of fuzzers' instances, it is necessary to merge these subgraphs.  
During actual testing, we found that AFLTeam had difficulty accessing certain subtasks of the tested program, which could potentially waste the fuzzing time of the fuzzing instances assigned to these subtasks. Therefore, unlike AFLTeam, we first merge the subgraphs that cannot be directly accessed by the \"main\" function in MST with the preceding subgraphs that can directly access those subgraphs. The result of this step is illustrated in Figure 5b. After that, merged subgraphs were arranged in descending order of the total weight of all functions contained in them, and the result was as shown in Figure 5c. Then, each subgraph was assigned to the subtask with the minimum total weight in turn to balance the expected workloads of each subtask, and the subtasks were as shown in Figure 5d. Finally, the merged subtasks were labeled on the callgraph, and the callgraph subgraphs representing each subtask were obtained as shown in Figure 5e.  
Further, the pseudocode for the subgraph merging algorithm is as follows (Algorithm 2):  
```
Input: CallGraph in Format of Minimum Spanning Tree \(MST\), A List Representing the Division Result \(plist\), the Number of Required Subtasks \(n\) Output: CallGraph with subtask label in Format of Minimum Spanning Tree \(MST\) function subgraphMerging(\(MST\), \(plist\))
1. // find a subgraph with the function named main in it
2. rootSubgraph = findMainFunc(\(plist\))
3. // merge subgraphs which cannot be called directly by the subgraph with the function named main in it
4. for p in \(plist\)do
5. if p!= rootSubgraph && p?=pre!= rootSubgraph do
6. merge(p, p?=pre)
7. end if
8. end for
9. // arrange subgraphs in \(plist\) according to their weight
10. sort(\(plist\))
11. // initialize subtasks and their weights
12. subtasks = [[]]
13. for i in range(\(n\)) do
14. totalWeights[i] = 0
15. end for
16. // assign the subgraphs in \(plist\) to the subtask with the smallest total weight at that time in turn
17. for p in \(plist\)do
18. no = getSubtaskWithMinWeight(totalWeight)
19. subtasks[no].append(p)
20. totalWeight[no] += p.weight
21. end for
22. // Append the subtask number to which each function belongs to the \(MST\)
23. for i in range(\(n\)) do
24. for node in subtasks[i] do
25. \(MST\)[node]['subtask'] = i
26. end for
27. end for
28. return \(MST\) end function
```  
**Algorithm 2**Subgraph Merging  
Remarks on the subgraph merging algorithm are as follows: Firstly, the subgraph containing the \"main\" function (line 2) was located, and the remaining subgraphs that cannot be called by the subgraph containing the \"main\" function directly were merged with the subgraph that can directly call this subgraph (lines 4 to 8). Then, the merged subgraphs were arranged in descending order of the total weight of all functions included (line 10), and each subgraph was assigned to the subtask with the minimum total weight  
Figure 5: A sample of subgraph merging. (**a**) A sample of the result of callgraph partitioning. (**b**) The result of merging the subgraphs that cannot be directly called by the main function with the one that can directly call it. (**c**) The result of arranging the subgraphs in descending order of weight. (**d**) The result of subgraph merging (in chart). (**e**) The result of subgraph merging marked in the callgraph.  
at that time in order (lines 17 to 21). Finally, the subtask number that each function node belongs to was attached to the node of the MST (lines 23 to 27).