Well, it is CPU utilization that heats up the cores, so it is a code that runs on a CPU, regardless of what sybsystem or driver it belongs to.
Looking at spindump during the indexing stage: out of 10 seconds this thread unsurprisingly took about 7 seconds of CPU time:
Thread 0x1dc823 1000 samples (1-1000) priority 31-46 (base 31) cpu time 7.107s (24.7G cycles, 33.6G instructions, 0.74c/i)
992 runtime.main + 519 (duplicacy + 196007) [0x402fda7]
992 main.main + 21694 (duplicacy + 8262430) [0x47e131e]
992 github.com/gilbertchen/cli.(*App).Run + 1617 (duplicacy + 3513441) [0x4359c61]
992 github.com/gilbertchen/cli.Command.Run + 1905 (duplicacy + 3523649) [0x435c441]
992 main.backupRepository + 1471 (duplicacy + 8218735) [0x47d686f]
992 github.com/gilbertchen/duplicacy/src.(*BackupManager).Backup + 1236 (duplicacy + 7707156) [0x4759a14]
992 github.com/gilbertchen/duplicacy/src.CreateSnapshotFromDirectory + 988 (duplicacy + 7973420) [0x479aa2c]
But it is how that time is used is what is interesting. Going further down the stack those 992 samples are split between following stacks: 30% regex matching and 70% APFS kernel code:
One
566 github.com/gilbertchen/duplicacy/src.ListEntries + 2665 (duplicacy + 7844649) [0x477b329]
416 github.com/gilbertchen/duplicacy/src.(*Entry).ReadAttributes + 201 (duplicacy + 8139065) [0x47c3139]
376 github.com/gilbertchen/xattr.Listxattr + 77 (duplicacy + 7633837) [0x4747bad]
372 syscall.Syscall6 + 48 (duplicacy + 729408) [0x40b2140]
[ truncated calls into kernel and APFS driver ]
Two
226 github.com/gilbertchen/duplicacy/src.ListEntries + 4279 (duplicacy + 7846263) [0x477b977]
208 github.com/gilbertchen/duplicacy/src.MatchPath + 746 (duplicacy + 8132506) [0x47c179a]
208 regexp.(*Regexp).MatchString + 85 (duplicacy + 1250789) [0x41315e5]
208 regexp.(*Regexp).doMatch + 177 (duplicacy + 1237281) [0x412e121]
[ truncated user-mode stack all the way ]
Three
195 github.com/gilbertchen/duplicacy/src.ListEntries + 462 (duplicacy + 7842446) [0x477aa8e]
190 io/ioutil.ReadDir + 124 (duplicacy + 1757084) [0x41acf9c]
190 os.(*File).Readdir + 62 (duplicacy + 831966) [0x40cb1de]
155 os.(*File).readdir + 446 (duplicacy + 832734) [0x40cb4de]
155 os.Lstat + 77 (duplicacy + 864125) [0x40d2f7d]
155 os.lstatNolog + 92 (duplicacy + 865740) [0x40d35cc]
155 syscall.Syscall + 54 (duplicacy + 729302) [0x40b20d6]
[ another call into APFS, also truncated ]
So yes, I guess if we could insert throttling in the loop in ListEntries
it would help tremendously improve user experience: there is absolutely no hurry to burn CPU to backup ASAP, especially with filesystem snapshot support already in place. (If anything, even Time Machine takes ages to backup – I think it is deliberate for the similar reasons.)