WEBVTT captioned by sachac NOTE Introduction 00:00:00.000 --> 00:00:04.639 Hello everyone, my name is Ihor Radchenko, 00:00:04.640 --> 00:00:07.599 and you may know me from Org Mailing List. 00:00:07.600 --> 00:00:09.799 However, today I'm not going to talk about Org Mode. 00:00:09.800 --> 00:00:11.919 Today I'm going to talk about 00:00:11.920 --> 00:00:14.959 Emacs performance and how it's affected 00:00:14.960 --> 00:00:19.039 by its memory management code. 00:00:19.040 --> 00:00:21.639 First, I will introduce the basic concepts 00:00:21.640 --> 00:00:26.439 of Emacs memory management and what garbage collection is. 00:00:26.440 --> 00:00:30.559 Then I will show you user statistics 00:00:30.560 --> 00:00:34.959 collected from volunteer users over the last half year 00:00:34.960 --> 00:00:39.319 and I will end with some guidelines 00:00:39.320 --> 00:00:44.719 on how to tweak Emacs garbage collection customizations 00:00:44.720 --> 00:00:47.479 to optimize Emacs performance 00:00:47.480 --> 00:00:51.079 and when it's necessary or not to do. NOTE About garbage collection in Emacs 00:00:51.080 --> 00:00:54.519 Let's begin. What is garbage collection? 00:00:54.520 --> 00:00:56.519 To understand what is garbage collection, 00:00:56.520 --> 00:00:59.039 we need to realize that anything you do in Emacs 00:00:59.040 --> 00:01:02.119 is some kind of command. Any command is most likely 00:01:02.120 --> 00:01:05.839 running some Elisp code. Every time you run Elisp code, 00:01:05.840 --> 00:01:09.239 you most likely need to locate certain memory in RAM. 00:01:09.240 --> 00:01:12.879 Some of this memory is retained for a long time 00:01:12.880 --> 00:01:15.559 and some of this memory is transient. 00:01:15.560 --> 00:01:19.119 Of course, Emacs has to clear this transient memory 00:01:19.120 --> 00:01:21.439 from time to time, to not occupy all the possible RAM 00:01:21.440 --> 00:01:21.447 in the computer. In this small example, 00:01:21.448 --> 00:01:28.639 we have one global variable 00:01:28.640 --> 00:01:31.279 that is assigned a value, 00:01:31.280 --> 00:01:33.079 but when assigning the value, 00:01:33.080 --> 00:01:35.679 we first allocate a temporary variable 00:01:35.680 --> 00:01:37.119 and then a temporary list 00:01:37.120 --> 00:01:40.079 and only retain some part of this list 00:01:40.080 --> 00:01:42.079 in this global variable. 00:01:42.080 --> 00:01:44.799 In terms of memory graph 00:01:44.800 --> 00:01:50.359 we can represent this as two variable slots, 00:01:50.360 --> 00:01:53.159 one transient, one permanent, 00:01:53.160 --> 00:01:56.199 and then a list of three cons cells, 00:01:56.200 --> 00:02:01.959 part of which is retained as a global variable 00:02:01.960 --> 00:02:04.999 but part of it which is a temporary variable symbol. 00:02:05.000 --> 00:02:07.679 The first term of the list is not used 00:02:07.680 --> 00:02:09.759 and it might be cleared at some point. NOTE Garbage collection in Emacs 00:02:09.760 --> 00:02:12.239 So that's what Emacs does. 00:02:12.240 --> 00:02:15.919 Every now and then, Emacs goes through all the memory 00:02:15.920 --> 00:02:19.119 and identifies which part of the memory are not used 00:02:19.120 --> 00:02:23.759 and then clear them so that it can free up the RAM. 00:02:23.760 --> 00:02:25.919 This process is called garbage collection 00:02:25.920 --> 00:02:28.919 and Emacs uses a very simple and old algorithm 00:02:28.920 --> 00:02:30.559 which is called Mark & Sweep. 00:02:30.560 --> 00:02:33.759 So doing this mark and sweep process 00:02:33.760 --> 00:02:34.879 is basically two stages. 00:02:34.880 --> 00:02:40.039 First, Emacs scans all the memory that is allocated 00:02:40.040 --> 00:02:42.759 and then identifies which memory is still in use 00:02:42.760 --> 00:02:45.519 which is linked to some variables, for example, 00:02:45.520 --> 00:02:47.599 and which memory is not used anymore 00:02:47.600 --> 00:02:49.559 even though it was allocated in the past. 00:02:49.560 --> 00:02:52.999 The second stage [??] whenever a memory is not, 00:02:53.000 --> 00:02:59.319 that is not allocated. During the process 00:02:59.320 --> 00:03:00.759 Emacs cannot do anything now. 00:03:00.760 --> 00:03:04.159 So basically, every time Emacs scans the memory, 00:03:04.160 --> 00:03:07.199 it freezes up and doesn't respond to anything, 00:03:07.200 --> 00:03:10.959 and if it takes too much time so that users can notice it, 00:03:10.960 --> 00:03:13.399 then of course Emacs is not responsive at all, 00:03:13.400 --> 00:03:19.439 and if this garbage collection is triggered too frequently, 00:03:19.440 --> 00:03:22.399 then it's not just not responsive every now and then. 00:03:22.400 --> 00:03:24.679 It's also not responsive all the time, 00:03:24.680 --> 00:03:26.079 almost all the time, 00:03:26.080 --> 00:03:27.679 so it cannot even normally type or stuff 00:03:27.680 --> 00:03:32.439 or do some normal commands. 00:03:32.440 --> 00:03:36.719 This mark and sweep algorithm is taking longer 00:03:36.720 --> 00:03:40.199 the more memory Emacs uses. So basically, 00:03:40.200 --> 00:03:44.439 the more buffers you open, the more packages you load, 00:03:44.440 --> 00:03:48.319 the more complex commands you run, the more memory is used, 00:03:48.320 --> 00:03:52.279 and basically, the longer Emacs takes 00:03:52.280 --> 00:03:57.919 to perform a single garbage collection. 00:03:57.920 --> 00:04:02.279 Of course, Emacs being Emacs 00:04:02.280 --> 00:04:06.039 this garbage collection can be tweaked. 00:04:06.040 --> 00:04:08.279 In particular users can tweak 00:04:08.280 --> 00:04:10.639 how frequently Emacs does garbage collection 00:04:10.640 --> 00:04:13.879 using two basic variables: `gc-cons-threshold` 00:04:13.880 --> 00:04:15.519 and `gc-cons-percentage`. 00:04:15.520 --> 00:04:21.599 `gc-cons-threshold` is the raw number of kilobytes 00:04:21.600 --> 00:04:22.479 Emacs needs to allocate 00:04:22.480 --> 00:04:25.959 before triggering another garbage collection, 00:04:25.960 --> 00:04:27.799 and the `gc-cons-percentage` is similar, 00:04:27.800 --> 00:04:30.399 but it's defined in terms of fraction 00:04:30.400 --> 00:04:34.759 of already-allocated memory. 00:04:34.760 --> 00:04:38.239 If you follow various Emacs forums, 00:04:38.240 --> 00:04:41.959 you may be familiar with people complaining about 00:04:41.960 --> 00:04:46.479 garbage collection. There are many many suggestions 00:04:46.480 --> 00:04:48.039 about what to do with it. 00:04:48.040 --> 00:04:54.079 Most frequently, you see `gc-cons-threshold` 00:04:54.080 --> 00:04:56.879 recommended to be increased, 00:04:56.880 --> 00:05:01.439 and a number of pre-packaged Emacs distributions 00:05:01.440 --> 00:05:04.319 like Doom Emacs do increase it. 00:05:04.320 --> 00:05:07.279 I have seen suggestions which are actually horrible 00:05:07.280 --> 00:05:10.479 to disable garbage collection temporarily 00:05:10.480 --> 00:05:14.359 or for a long time. 00:05:14.360 --> 00:05:17.519 Which is nice... You can see it quite frequently, 00:05:17.520 --> 00:05:19.399 which indicates there might be some problem. 00:05:19.400 --> 00:05:23.959 However, every time one user poses about this problem, 00:05:23.960 --> 00:05:26.879 it's just one data point and it doesn't mean 00:05:26.880 --> 00:05:28.879 that everyone actually suffers from it. 00:05:28.880 --> 00:05:33.719 It doesn't mean that everyone should do it. 00:05:33.720 --> 00:05:35.919 So in order to understand if this garbage collection 00:05:35.920 --> 00:05:39.959 is really a problem which is a common problem 00:05:39.960 --> 00:05:44.919 we do need some kind of statistics 00:05:44.920 --> 00:05:46.919 and only using the actual statistics 00:05:46.920 --> 00:05:52.759 we can understand if it should be recommended for everyone 00:05:52.760 --> 00:05:54.999 to tweak the defaults or like whether 00:05:55.000 --> 00:05:57.159 it should be recommended for certain users 00:05:57.160 --> 00:05:59.479 or maybe it should be asked Emacs devs 00:05:59.480 --> 00:06:01.559 to do something about the defaults. 00:06:01.560 --> 00:06:07.959 And what I did some time ago is exactly this. 00:06:07.960 --> 00:06:09.959 I tried to collect the user statistics. 00:06:09.960 --> 00:06:14.519 So I wrote a small package on Elp 00:06:14.520 --> 00:06:18.159 and some users installed this package 00:06:18.160 --> 00:06:22.119 and then reported back these statistics 00:06:22.120 --> 00:06:24.279 of the garbage collection for their particular use. 00:06:24.280 --> 00:06:30.799 By now we have obtained 129 user submissions 00:06:30.800 --> 00:06:34.039 with over 1 million GC records in there. 00:06:34.040 --> 00:06:38.119 So like some of these submissions 00:06:38.120 --> 00:06:43.159 used default GC settings without any customizations. 00:06:43.160 --> 00:06:46.039 Some used increased GC cost threshold 00:06:46.040 --> 00:06:47.799 and GC cost percentage. 00:06:47.800 --> 00:06:53.319 So using this data we can try to draw 00:06:53.320 --> 00:06:56.879 some reliable conclusions on what should be done 00:06:56.880 --> 00:06:59.919 and whether should anything be done about garbage collection 00:06:59.920 --> 00:07:02.639 on Emacs dev level or at least on user level. 00:07:02.640 --> 00:07:05.639 Of course we need to keep in mind 00:07:05.640 --> 00:07:07.279 that there's some kind of bias 00:07:07.280 --> 00:07:08.999 because it's more likely 00:07:09.000 --> 00:07:11.719 that users already have problems with GC 00:07:11.720 --> 00:07:13.239 or they think they have problems with GC 00:07:13.240 --> 00:07:15.919 will report and submit the data. 00:07:15.920 --> 00:07:19.999 But anyway having s statistics is much more useful 00:07:20.000 --> 00:07:22.079 than just having anecdotal evidences 00:07:22.080 --> 00:07:25.519 from one or other reddit posts. 00:07:25.520 --> 00:07:28.759 And just one thing I will do 00:07:28.760 --> 00:07:30.879 during the rest of my presentation 00:07:30.880 --> 00:07:32.839 is that for all the statistics 00:07:32.840 --> 00:07:35.679 I will normalize user data 00:07:35.680 --> 00:07:37.879 so that every user contributes equally. 00:07:37.880 --> 00:07:40.279 For example if one user submits like 00:07:40.280 --> 00:07:43.119 100 hours Emacs uptime statistics 00:07:43.120 --> 00:07:46.279 and other users submit one hour Emacs uptime 00:07:46.280 --> 00:07:52.879 then I will anyway make it so that they contribute equally. 00:07:52.880 --> 00:07:56.359 Let's start from one of the most obvious things 00:07:56.360 --> 00:07:57.679 we can look into is 00:07:57.680 --> 00:08:00.599 which is the time it takes for garbage collection 00:08:00.600 --> 00:08:05.879 to single garbage collection process. 00:08:05.880 --> 00:08:11.839 Here you see frequency distribution of GC duration 00:08:11.840 --> 00:08:14.999 for all the 129 users we got 00:08:15.000 --> 00:08:22.279 and you can see that most of the garbage collections 00:08:22.280 --> 00:08:26.999 are done quite quickly in less than 0.1 second 00:08:27.000 --> 00:08:32.199 and less than 0.1 second is usually just not noticeable. 00:08:32.200 --> 00:08:34.519 So even though there is garbage collection 00:08:34.520 --> 00:08:39.639 it will not interrupt the work in Emacs. 00:08:39.640 --> 00:08:43.279 However there is a fraction of users 00:08:43.280 --> 00:08:45.279 who experience garbage collection 00:08:45.280 --> 00:08:48.399 it takes like 0.2, 0.3 or even half a second 00:08:48.400 --> 00:08:50.399 which will be quite noticeable. 00:08:50.400 --> 00:08:55.279 For the purposes of this study 00:08:55.280 --> 00:08:59.399 I will consider that anything that is less than 0.1 second 00:08:59.400 --> 00:09:02.639 which is insignificant so like you will not notice it 00:09:02.640 --> 00:09:04.159 and it's like obviously 00:09:04.160 --> 00:09:07.479 all the Emacs usage will be just normal. 00:09:07.480 --> 00:09:11.639 But if it's more than 0.1 or 0.2 seconds 00:09:11.640 --> 00:09:13.799 then it will be very noticeable 00:09:13.800 --> 00:09:16.079 and you will see that Emacs hang for a little while 00:09:16.080 --> 00:09:21.319 or not so little while. In terms of numbers 00:09:21.320 --> 00:09:26.239 it's better to plot the statistics not as a distribution 00:09:26.240 --> 00:09:28.199 but as a cumulative distribution. 00:09:28.200 --> 00:09:31.559 So like at every point of this graph 00:09:31.560 --> 00:09:37.159 you'll see like for example here 0.4 seconds 00:09:37.160 --> 00:09:42.279 you have this percent of like almost 90% of users 00:09:42.280 --> 00:09:49.279 have no more than 0.4 gc duration. 00:09:49.280 --> 00:09:53.239 So like we can look here if we take one 00:09:53.240 --> 00:09:56.879 gc critical gc duration which is 0.1 second 00:09:56.880 --> 00:10:00.279 0.1 second and look at how many users have 00:10:00.280 --> 00:10:02.439 it so we have 56% which is like 00:10:02.440 --> 00:10:09.439 44% users have less than 0.1 second gc duration 00:10:09.440 --> 00:10:12.839 and the rest 56% have more than 0.1 second. 00:10:12.840 --> 00:10:16.279 So you can see like more than half of users 00:10:16.280 --> 00:10:20.559 actually have noticeable gc delay 00:10:20.560 --> 00:10:22.999 so the Emacs freezes for some noticeable time 00:10:23.000 --> 00:10:27.479 and a quarter of users actually have very noticeable 00:10:27.480 --> 00:10:31.799 so like Emacs freezes such that you see an actual delay 00:10:31.800 --> 00:10:36.879 that Emacs actually has 00:10:36.880 --> 00:10:44.079 which is quite significant and important point. 00:10:44.080 --> 00:10:47.719 But apart from the duration of each individual gc 00:10:47.720 --> 00:10:49.839 it is important to see how frequent it is 00:10:49.840 --> 00:10:52.879 because even if you do notice a delay 00:10:52.880 --> 00:10:54.959 even a few seconds delay 00:10:54.960 --> 00:10:56.999 it doesn't matter if it happens once 00:10:57.000 --> 00:10:59.199 during the whole Emacs session. 00:10:59.200 --> 00:11:05.039 So if you look into frequency distribution again here 00:11:05.040 --> 00:11:13.639 I plot time between subsequent garbage collections 00:11:13.640 --> 00:11:17.959 versus how frequent it is and we have very clear trend 00:11:17.960 --> 00:11:21.799 that most of the garbage collections are quite frequent 00:11:21.800 --> 00:11:25.159 like we talk about every few seconds a few tens of seconds. 00:11:25.160 --> 00:11:30.039 There's a few outliers which are at very round numbers 00:11:30.040 --> 00:11:35.839 like 60 seconds, 120 seconds, 300 seconds. 00:11:35.840 --> 00:11:37.879 These are usually timers so like 00:11:37.880 --> 00:11:40.319 you have something running on timer 00:11:40.320 --> 00:11:43.599 and then it is complex command 00:11:43.600 --> 00:11:45.079 and it triggers garbage collection 00:11:45.080 --> 00:11:48.079 but it's not the majority. 00:11:48.080 --> 00:11:51.279 Again to run the numbers 00:11:51.280 --> 00:11:53.679 it's better to look into cumulative distribution 00:11:53.680 --> 00:11:56.039 and see that 50% of garbage collections 00:11:56.040 --> 00:11:58.279 are basically less than 10 seconds apart. 00:11:58.280 --> 00:12:02.359 And we can combine it with previous data 00:12:02.360 --> 00:12:07.479 and we look into whatever garbage collection 00:12:07.480 --> 00:12:09.959 takes less than 10 seconds from each other 00:12:09.960 --> 00:12:13.119 and also takes more than say 0.1 seconds. 00:12:13.120 --> 00:12:15.319 So and then we see that 00:12:15.320 --> 00:12:17.639 one quarter of all garbage collections 00:12:17.640 --> 00:12:21.039 are just noticeable and also frequent 00:12:21.040 --> 00:12:23.679 and 9% are not like 00:12:23.680 --> 00:12:27.199 more than 0.2% very noticeable and also frequent. 00:12:27.200 --> 00:12:30.079 So basically it constitutes Emacs freezing. 00:12:30.080 --> 00:12:33.559 So 9% of all the garbage collection Emacs freezing. 00:12:33.560 --> 00:12:37.319 Of course if you remember there is a bias 00:12:37.320 --> 00:12:40.519 but 9% is quite significant number. 00:12:40.520 --> 00:12:44.319 So garbage collection can really slow down things 00:12:44.320 --> 00:12:48.239 not for everyone but for significant fraction of users. 00:12:48.240 --> 00:12:52.159 Another thing I'd like to look into 00:12:52.160 --> 00:12:55.399 is what I call agglomerated GCs. 00:12:55.400 --> 00:12:57.959 What I mean by agglomerated is 00:12:57.960 --> 00:13:00.359 when you have one garbage collection 00:13:00.360 --> 00:13:02.999 and then another garbage immediately after it. 00:13:03.000 --> 00:13:05.559 So in terms of numbers I took 00:13:05.560 --> 00:13:08.719 every subsequent garbage collection 00:13:08.720 --> 00:13:10.399 which is either immediately after 00:13:10.400 --> 00:13:13.039 or no more than one second after each. 00:13:13.040 --> 00:13:16.159 So from point of view of users is like 00:13:16.160 --> 00:13:19.999 multiple garbage collection they add up together 00:13:20.000 --> 00:13:22.999 into one giant garbage collection. 00:13:23.000 --> 00:13:25.839 And if you look into numbers 00:13:25.840 --> 00:13:29.559 of how many agglomerated garbage collections there are 00:13:29.560 --> 00:13:32.119 you can see even numbers over 100. 00:13:32.120 --> 00:13:35.479 So 100 garbage collection going one after another. 00:13:35.480 --> 00:13:39.159 Even if you think about each garbage collection 00:13:39.160 --> 00:13:42.719 taking 0.1 second we look into 100 of them 00:13:42.720 --> 00:13:44.639 it's total 10 seconds. 00:13:44.640 --> 00:13:46.839 It's like Emacs hanging forever 00:13:46.840 --> 00:13:53.519 or like a significant number is also 10. 00:13:53.520 --> 00:13:55.999 So again this would be very annoying to meet such thing. 00:13:56.000 --> 00:13:57.879 How frequently does it happen? 00:13:57.880 --> 00:14:00.279 Again we can plot cumulative distribution 00:14:00.280 --> 00:14:03.879 and we see that 20 percent like 19 percent 00:14:03.880 --> 00:14:07.199 of all the garbage collection are at least two together 00:14:07.200 --> 00:14:13.679 and 8 percent like more than 10. So like you think about oh 00:14:13.680 --> 00:14:15.639 each garbage collection is not taking much time 00:14:15.640 --> 00:14:24.479 but when you have 10 of them yeah that becomes a problem. 00:14:24.480 --> 00:14:29.919 Another thing is to answer a question 00:14:29.920 --> 00:14:32.959 that some people complain about is that 00:14:32.960 --> 00:14:35.799 longer you use Emacs the slower Emacs become. 00:14:35.800 --> 00:14:43.039 Of course it may be caused by garbage collection 00:14:43.040 --> 00:14:48.519 and I wanted to look into how garbage collection time 00:14:48.520 --> 00:14:49.679 and other statistics, 00:14:49.680 --> 00:14:53.199 other parameters are evolving over time. 00:14:53.200 --> 00:14:58.559 And what I can see here is a cumulative distribution 00:14:58.560 --> 00:15:03.719 of GC duration for like first 10 minutes of Emacs uptime 00:15:03.720 --> 00:15:06.479 first 100 minutes first 1000 minutes. 00:15:06.480 --> 00:15:10.199 And if you look closer then you see 00:15:10.200 --> 00:15:14.519 that each individual garbage collection on average 00:15:14.520 --> 00:15:18.959 takes longer as you use Emacs longer. 00:15:18.960 --> 00:15:24.039 However this longer is not much it's like maybe 10 percent 00:15:24.040 --> 00:15:29.479 like basically garbage collection gets like 00:15:29.480 --> 00:15:34.719 slow Emacs down more as you use Emacs more but not much. 00:15:34.720 --> 00:15:38.359 So basically if you do you see Emacs 00:15:38.360 --> 00:15:40.639 being slower and slower over time 00:15:40.640 --> 00:15:43.159 it's probably not really garbage collection 00:15:43.160 --> 00:15:45.839 because it doesn't change too much. 00:15:45.840 --> 00:15:48.119 And if you look into time 00:15:48.120 --> 00:15:50.839 between individual garbage collections 00:15:50.840 --> 00:15:53.719 and you see that the time actually increases 00:15:53.720 --> 00:15:56.719 as you use Emacs longer which makes sense 00:15:56.720 --> 00:15:58.839 because initially like first few minutes 00:15:58.840 --> 00:16:01.479 you have all kind of packages loading 00:16:01.480 --> 00:16:04.239 like all the port loading and then later 00:16:04.240 --> 00:16:07.239 everything is loaded and things become more stable. 00:16:07.240 --> 00:16:12.879 So the conclusion on this part is that 00:16:12.880 --> 00:16:16.399 if Emacs becomes slower in a long session 00:16:16.400 --> 00:16:18.479 it's probably not caused by garbage collection. 00:16:18.480 --> 00:16:23.679 And one word of warning of course is that 00:16:23.680 --> 00:16:27.919 it's all nice and all when I present the statistics 00:16:27.920 --> 00:16:29.279 but it's only an average 00:16:29.280 --> 00:16:34.079 and if you are an actual user like here is one example 00:16:34.080 --> 00:16:37.159 which shows a total garbage collection time 00:16:37.160 --> 00:16:40.119 like accumulated together over Emacs uptime 00:16:40.120 --> 00:16:43.199 and you see different lines 00:16:43.200 --> 00:16:45.559 which correspond to different sessions of one user 00:16:45.560 --> 00:16:48.679 and you see they are wildly different 00:16:48.680 --> 00:16:51.439 like one time there is almost no garbage collection 00:16:51.440 --> 00:16:54.679 another time you see garbage collection 00:16:54.680 --> 00:16:56.999 because probably Emacs is used more early 00:16:57.000 --> 00:16:59.599 or like different pattern of usage 00:16:59.600 --> 00:17:03.159 and even during a single Emacs session 00:17:03.160 --> 00:17:04.599 you see a different slope 00:17:04.600 --> 00:17:06.439 of this curve which means that 00:17:06.440 --> 00:17:09.279 sometimes garbage collection is infrequent 00:17:09.280 --> 00:17:11.479 and sometimes it's much more frequent 00:17:11.480 --> 00:17:14.479 so it's probably much more noticeable one time 00:17:14.480 --> 00:17:15.639 and less noticeable other time. 00:17:15.640 --> 00:17:19.719 So if you think about these statistics of course 00:17:19.720 --> 00:17:23.359 they only represent an average usage 00:17:23.360 --> 00:17:26.359 but sometimes it can get worse sometimes it can get better. 00:17:26.360 --> 00:17:33.759 The last parameter I'd like to talk about is 00:17:33.760 --> 00:17:35.799 garbage collection during Emacs init. 00:17:35.800 --> 00:17:40.439 Basically if you think about what happens during Emacs init 00:17:40.440 --> 00:17:41.919 like when Emacs just starting up 00:17:41.920 --> 00:17:44.479 then whatever garbage collection 00:17:44.480 --> 00:17:46.759 there it's one or it's several times 00:17:46.760 --> 00:17:51.239 it all contributes to Emacs taking longer to start. 00:17:51.240 --> 00:17:56.559 And again we can look into the statistic 00:17:56.560 --> 00:18:01.159 and see what is the total GC duration after Emacs init 00:18:01.160 --> 00:18:06.159 and we see that 50% of all the submissions 00:18:06.160 --> 00:18:10.279 garbage collection adds up more than one second 00:18:10.280 --> 00:18:14.919 to Emacs init time and for 20% of users 00:18:14.920 --> 00:18:17.079 it's extra three seconds Emacs start time 00:18:17.080 --> 00:18:18.479 which is very significant 00:18:18.480 --> 00:18:21.479 especially for people who are used to Vim 00:18:21.480 --> 00:18:23.919 which can start in like a fraction of a second 00:18:23.920 --> 00:18:26.239 and here it just does garbage collection 00:18:26.240 --> 00:18:27.439 because garbage collection is not 00:18:27.440 --> 00:18:29.239 everything Emacs does during startup 00:18:29.240 --> 00:18:31.999 adds up more to the load. 00:18:32.000 --> 00:18:36.119 Okay that's all nice and all 00:18:36.120 --> 00:18:38.679 but what can we do about these statistics 00:18:38.680 --> 00:18:40.159 can we draw any conclusions 00:18:40.160 --> 00:18:43.239 and the answer is of course 00:18:43.240 --> 00:18:46.079 like the most important conclusion here is that 00:18:46.080 --> 00:18:49.439 yes garbage collection can slow down Emacs 00:18:49.440 --> 00:18:52.679 at least for some people and what to do about it 00:18:52.680 --> 00:18:55.319 there are two variables which you can tweak 00:18:55.320 --> 00:18:58.719 it's because gcconce threshold gcconce percentage 00:18:58.720 --> 00:19:03.159 and having the statistics I can at least look a little bit 00:19:03.160 --> 00:19:08.879 into what is the effect of increasing these variables 00:19:08.880 --> 00:19:12.439 like most people just increase gcconce threshold 00:19:12.440 --> 00:19:16.959 and like all the submissions people did increase 00:19:16.960 --> 00:19:19.919 and doesn't make much sense to decrease it 00:19:19.920 --> 00:19:21.079 like to make things worse 00:19:21.080 --> 00:19:27.639 of course for these statistics 00:19:27.640 --> 00:19:31.559 the exact values of this increased thresholds 00:19:31.560 --> 00:19:33.839 are not always the same 00:19:33.840 --> 00:19:36.479 but at least we can look into some trends 00:19:36.480 --> 00:19:44.759 so first and obvious thing we can observe 00:19:44.760 --> 00:19:46.759 is when we compare 00:19:46.760 --> 00:19:50.399 the standard gc settings standard thresholds 00:19:50.400 --> 00:19:53.999 and increased thresholds for time between 00:19:54.000 --> 00:19:57.479 subsequent gcs and as one may expect 00:19:57.480 --> 00:19:59.559 if you increase the threshold 00:19:59.560 --> 00:20:02.679 Emacs will do garbage collection less frequently 00:20:02.680 --> 00:20:05.279 so the spacing between garbage collection increases 00:20:05.280 --> 00:20:07.599 okay the only thing is that 00:20:07.600 --> 00:20:10.719 if garbage collection is less frequent 00:20:10.720 --> 00:20:14.079 then each individual garbage collection becomes longer 00:20:14.080 --> 00:20:18.159 so if you think about increasing 00:20:18.160 --> 00:20:22.239 garbage collection thresholds be prepared 00:20:22.240 --> 00:20:26.519 that in each individual time Emacs freezes will take longer 00:20:26.520 --> 00:20:31.599 this is one caveat when we talk about 00:20:31.600 --> 00:20:34.079 this agglomerated gcs which are one after other 00:20:34.080 --> 00:20:36.759 like if you increase the threshold sufficiently 00:20:36.760 --> 00:20:42.319 then whatever happened that garbage collections 00:20:42.320 --> 00:20:44.399 were like done one after other 00:20:44.400 --> 00:20:47.599 we can now make it so that they are actually separated 00:20:47.600 --> 00:20:51.559 so like you don't see one giant freeze caused by 00:20:51.560 --> 00:20:52.919 like 10 gcs in a row 00:20:52.920 --> 00:20:55.759 instead you can make it so that they are separated 00:20:55.760 --> 00:20:59.079 and in statistics it's very clear 00:20:59.080 --> 00:21:02.959 that the number of agglomerated garbage collections 00:21:02.960 --> 00:21:06.919 decreases dramatically when you increase the thresholds 00:21:06.920 --> 00:21:11.759 it's particularly evident when we look into startup time 00:21:11.760 --> 00:21:17.279 if you look at gc duration during Emacs startup 00:21:17.280 --> 00:21:19.159 and if we look into what happens 00:21:19.160 --> 00:21:20.879 when you increase the thresholds 00:21:20.880 --> 00:21:23.799 it's very clear that Emacs startup become faster 00:21:23.800 --> 00:21:26.279 when you increase gc thresholds 00:21:26.280 --> 00:21:33.359 so that's all for actual user statistics 00:21:33.360 --> 00:21:35.439 and now let's try to run into 00:21:35.440 --> 00:21:38.079 some like actual recommendations 00:21:38.080 --> 00:21:42.639 on what numbers to set and before we start 00:21:42.640 --> 00:21:44.399 let me explain a little bit about 00:21:44.400 --> 00:21:46.479 the difference between these two variables 00:21:46.480 --> 00:21:48.879 which is gc constant threshold and gc constant percentage 00:21:48.880 --> 00:21:52.359 so if you think about Emacs memory 00:21:52.360 --> 00:21:55.239 like there's a certain memory allocated by Emacs 00:21:55.240 --> 00:21:58.479 and then as you run commands and turn using Emacs 00:21:58.480 --> 00:22:00.079 there is more memory allocated 00:22:00.080 --> 00:22:04.639 and Emacs decides when to do garbage collection 00:22:04.640 --> 00:22:06.079 according these two variables 00:22:06.080 --> 00:22:08.759 and actually what it does it chooses the larger one 00:22:08.760 --> 00:22:12.119 so say you have you are late in Emacs session 00:22:12.120 --> 00:22:14.039 you have a lot of Emacs memory allocated 00:22:14.040 --> 00:22:17.119 then you have gc constant percentage 00:22:17.120 --> 00:22:19.919 which is percent of the already allocated memory 00:22:19.920 --> 00:22:25.119 and that percent is probably going to be the largest 00:22:25.120 --> 00:22:28.319 because you have more memory 00:22:28.320 --> 00:22:32.559 and memory means that percent of it is larger 00:22:32.560 --> 00:22:36.359 so like you have a larger number cost 00:22:36.360 --> 00:22:37.719 by gc constant percentage 00:22:37.720 --> 00:22:43.079 so in this scenario when Emacs session is already running 00:22:43.080 --> 00:22:45.319 for a long time and there is a lot of memory allocated 00:22:45.320 --> 00:22:50.119 you have gc constant percentage 00:22:50.120 --> 00:22:52.279 controlling the garbage collection 00:22:52.280 --> 00:22:54.999 while early in Emacs there is not much memory placed 00:22:55.000 --> 00:22:58.719 Emacs just starting up then gc constant threshold 00:22:58.720 --> 00:23:01.639 is controlling how frequently garbage collection happens 00:23:01.640 --> 00:23:04.799 because smaller allocated memory 00:23:04.800 --> 00:23:06.839 means its percentage will be a small number 00:23:06.840 --> 00:23:12.319 so in terms of default values at least 00:23:12.320 --> 00:23:14.239 gc constant threshold is 800 kilobytes 00:23:14.240 --> 00:23:18.799 and gc constant percentage is 10 00:23:18.800 --> 00:23:24.159 so gc constant percentage becomes larger than that threshold 00:23:24.160 --> 00:23:28.919 when you have more than eight megabytes of allocated memory 00:23:28.920 --> 00:23:31.039 by Emacs which is quite early 00:23:31.040 --> 00:23:34.279 and it will probably hold just during the startup 00:23:34.280 --> 00:23:36.799 and once you start using your maximum 00:23:36.800 --> 00:23:38.919 and once you load all the histories 00:23:38.920 --> 00:23:42.039 all the kinds of buffers it's probably going to take 00:23:42.040 --> 00:23:43.959 more than much more than eight megabytes 00:23:43.960 --> 00:23:50.639 so now we understand this 00:23:50.640 --> 00:23:53.279 we can draw certain recommendations 00:23:53.280 --> 00:23:57.279 about tweaking the gc thresholds 00:23:57.280 --> 00:24:01.159 so first of all I need to emphasize 00:24:01.160 --> 00:24:03.639 that any time you increase gc threshold 00:24:03.640 --> 00:24:07.199 an individual garbage collection time increases 00:24:07.200 --> 00:24:08.759 so it's not free at all 00:24:08.760 --> 00:24:10.999 if you don't have problems with garbage collection 00:24:11.000 --> 00:24:13.519 which is half of the users don't have much problem 00:24:13.520 --> 00:24:15.079 you don't need to tweak anything 00:24:15.080 --> 00:24:19.359 only when gc is frequent and slow 00:24:19.360 --> 00:24:23.399 when Emacs is really really present frequently 00:24:23.400 --> 00:24:27.119 you may consider increasing gc thresholds only 00:24:27.120 --> 00:24:31.479 and in particular I recommend 00:24:31.480 --> 00:24:33.279 increasing gc constant percentage 00:24:33.280 --> 00:24:36.359 because that's what mostly controls gc 00:24:36.360 --> 00:24:40.079 when Emacs is running for long session 00:24:40.080 --> 00:24:43.039 and the numbers are probably like 00:24:43.040 --> 00:24:46.519 yeah we can estimate the effect of these numbers 00:24:46.520 --> 00:24:49.679 like for example if you have a default value of 0.1 percent 00:24:49.680 --> 00:24:52.759 for gc constant percentage 0.1 which is 10 percent 00:24:52.760 --> 00:24:55.039 and then increase it twice 00:24:55.040 --> 00:24:58.639 obviously you get twice less frequent gcs 00:24:58.640 --> 00:25:02.559 but it will come at the cost of extra 10 percent gc time 00:25:02.560 --> 00:25:05.839 and if you increase 10 times you can think about 00:25:05.840 --> 00:25:08.719 10 less 10 x less frequent gcs 00:25:08.720 --> 00:25:12.199 but almost twice longer individual garbage collection time 00:25:12.200 --> 00:25:16.919 so probably you want to set the number closer to 0.1 00:25:16.920 --> 00:25:23.399 another part of the users may actually 00:25:23.400 --> 00:25:28.359 try to optimize Emacs startup time 00:25:28.360 --> 00:25:30.759 which is quite frequent problem 00:25:30.760 --> 00:25:34.919 in this case it's probably better to increase gc constant 00:25:34.920 --> 00:25:38.199 but not too much so like 00:25:38.200 --> 00:25:40.239 first of all it makes sense to check 00:25:40.240 --> 00:25:43.319 whether garbage collection is a problem at all 00:25:43.320 --> 00:25:45.999 during startup and there are two variables 00:25:46.000 --> 00:25:50.199 which can show what is happening this garbage collection 00:25:50.200 --> 00:25:53.719 so gc done is a variable that shows 00:25:53.720 --> 00:25:55.039 how many garbage collection 00:25:55.040 --> 00:26:00.159 like what is the number of garbage collections triggered 00:26:00.160 --> 00:26:02.599 like when you check the value 00:26:02.600 --> 00:26:04.039 or right after you start Emacs 00:26:04.040 --> 00:26:04.799 you will see that 00:26:04.800 --> 00:26:08.519 number and gc elapsed variable 00:26:08.520 --> 00:26:11.599 which gives you a number of seconds 00:26:11.600 --> 00:26:14.959 which Emacs spent in doing garbage collection 00:26:14.960 --> 00:26:16.879 so this is probably the most important variable 00:26:16.880 --> 00:26:20.719 and if you see it's large then you may consider tweaking it 00:26:20.720 --> 00:26:26.799 for the Emacs startup we can estimate some bounds 00:26:26.800 --> 00:26:30.039 because in the statistics I never saw anything 00:26:30.040 --> 00:26:32.439 that is more than 10 seconds extra 00:26:32.440 --> 00:26:34.439 which even 10 seconds is probably like 00:26:34.440 --> 00:26:39.119 a really really hard upper bound so 00:26:39.120 --> 00:26:44.479 or say if you want to decrease the gc contribution 00:26:44.480 --> 00:26:47.479 like order of magnitude or like two orders of magnitudes 00:26:47.480 --> 00:26:50.879 let's say like as a really hard top estimate 00:26:50.880 --> 00:26:55.079 then it corresponds to 80 megabytes gc constant 00:26:55.080 --> 00:26:58.959 and probably much less so like 00:26:58.960 --> 00:27:00.679 there's no point setting it 00:27:00.680 --> 00:27:04.159 to a few hundred megabytes of course 00:27:04.160 --> 00:27:08.439 there's one caveat which is important to keep in 00:27:08.440 --> 00:27:14.039 mind though that increasing the gc thresholds 00:27:14.040 --> 00:27:16.399 is not just increasing individual gc time 00:27:16.400 --> 00:27:20.399 there's also an actual real impact on the RAM usage 00:27:20.400 --> 00:27:23.839 so like if you increase gc threshold 00:27:23.840 --> 00:27:26.879 it increases the RAM usage of Emacs 00:27:26.880 --> 00:27:29.639 and you shouldn't think that like okay 00:27:29.640 --> 00:27:33.159 I increased the threshold by like 100 megabytes 00:27:33.160 --> 00:27:37.119 then 100 megabytes extra RAM usage doesn't matter 00:27:37.120 --> 00:27:38.679 it's not 100 megabytes 00:27:38.680 --> 00:27:42.319 because less frequent garbage collection means 00:27:42.320 --> 00:27:45.639 it will lead to memory fragmentation 00:27:45.640 --> 00:27:50.439 so in practice if you increase the thresholds 00:27:50.440 --> 00:27:52.799 to tens or hundreds of megabytes 00:27:52.800 --> 00:27:55.919 we are talking about gigabytes extra RAM usage 00:27:55.920 --> 00:27:59.719 for me personally when I tried to play with gc thresholds 00:27:59.720 --> 00:28:02.879 I have seen Emacs taking two gigabytes like 00:28:02.880 --> 00:28:05.519 compared to several times less 00:28:05.520 --> 00:28:09.039 when with default settings so it's not free at all 00:28:09.040 --> 00:28:13.639 and only like either when you have a lot of free RAM 00:28:13.640 --> 00:28:16.839 and you don't care or when your Emacs is really slow 00:28:16.840 --> 00:28:19.559 then you may need to consider this 00:28:19.560 --> 00:28:23.239 tweaking these defaults so again don't tweak defaults 00:28:23.240 --> 00:28:24.239 if you don't really have a problem 00:28:24.240 --> 00:28:29.839 and of course this RAM problem is a big big deal 00:28:29.840 --> 00:28:35.679 for Emacs devs because from from the point of single user 00:28:35.680 --> 00:28:38.839 you have like normal laptop most likely like normal PC 00:28:38.840 --> 00:28:42.079 with a lot of RAM you don't care about these things too much 00:28:42.080 --> 00:28:48.999 but Emacs in general can run on like all kinds of machines 00:28:49.000 --> 00:28:51.679 including low-end machines with very limited RAM 00:28:51.680 --> 00:28:55.359 and anytime Emacs developers consider increasing 00:28:55.360 --> 00:28:57.959 the defaults for garbage collection 00:28:57.960 --> 00:29:01.479 it's like they always have to consider 00:29:01.480 --> 00:29:02.959 if you increase them too much 00:29:02.960 --> 00:29:07.919 then Emacs may just stop running on certain platforms 00:29:07.920 --> 00:29:14.439 so that's a very big consideration in terms 00:29:14.440 --> 00:29:16.639 of the global defaults for everyone 00:29:16.640 --> 00:29:22.199 although I have to I would say that it might be related 00:29:22.200 --> 00:29:24.479 to the safe to increase GCCons threshold 00:29:24.480 --> 00:29:27.919 because it mostly affects startup and during startup 00:29:27.920 --> 00:29:31.279 it's probably not the peak usage of Emacs 00:29:31.280 --> 00:29:35.599 and like as Emacs runs for longer 00:29:35.600 --> 00:29:38.199 it's probably where most of RAM will be used later 00:29:38.200 --> 00:29:44.399 on the other hand GCCons percentage is much more debating 00:29:44.400 --> 00:29:46.159 because it has pros and cons 00:29:46.160 --> 00:29:47.719 it will increase the RAM usage 00:29:47.720 --> 00:29:50.999 it will increase the individual GC time so 00:29:51.000 --> 00:29:56.119 if we consider changing it it's much more tricky 00:29:56.120 --> 00:29:59.479 and we have discussing probably measure the impact on users 00:29:59.480 --> 00:30:05.799 and a final note on or from the point of view 00:30:05.800 --> 00:30:07.319 of Emacs development is 00:30:07.320 --> 00:30:11.039 that this simple mark-and-sweep algorithm 00:30:11.040 --> 00:30:14.119 is like a very old and not the state-of-the-art algorithm 00:30:14.120 --> 00:30:17.799 there are variants of garbage collection 00:30:17.800 --> 00:30:19.479 that are like totally non-blocking 00:30:19.480 --> 00:30:22.479 so Emacs just doesn't have to freeze 00:30:22.480 --> 00:30:24.279 during the garbage collection 00:30:24.280 --> 00:30:26.839 or there are variants of garbage collection algorithm 00:30:26.840 --> 00:30:30.079 that do not scan all the memory just fraction of it 00:30:30.080 --> 00:30:33.439 and scan another fraction less frequently 00:30:33.440 --> 00:30:36.999 so there are actually ways just to change 00:30:37.000 --> 00:30:39.799 the garbage collection algorithm to make things much faster 00:30:39.800 --> 00:30:44.199 of course like just changing the numbers of variables 00:30:44.200 --> 00:30:47.079 like the numbers of variable values 00:30:47.080 --> 00:30:50.079 is much more tricky and one has to implement it 00:30:50.080 --> 00:30:52.239 obviously it would be nice if someone implements it 00:30:52.240 --> 00:30:55.639 but so far it's not happening so yeah it would be nice 00:30:55.640 --> 00:30:59.359 but maybe not not so quickly 00:30:59.360 --> 00:31:02.159 there is more chance to change the defaults here 00:31:02.160 --> 00:31:07.479 to conclude let me reiterate the most important points 00:31:07.480 --> 00:31:11.919 so from point of view of users you need to understand that 00:31:11.920 --> 00:31:14.479 yes garbage collection may be a problem 00:31:14.480 --> 00:31:16.679 but not for everyone so like 00:31:16.680 --> 00:31:21.079 you should only think about changing the variables 00:31:21.080 --> 00:31:23.559 when you really know that garbage collection 00:31:23.560 --> 00:31:27.479 is the problem for you so if you have slow Emacs startup 00:31:27.480 --> 00:31:30.919 slow Emacs startup and you know that it's caused by 00:31:30.920 --> 00:31:32.479 garbage collection like by 00:31:32.480 --> 00:31:35.999 you can check the GC elapsed variable 00:31:36.000 --> 00:31:39.679 then you may increase GC count threshold 00:31:39.680 --> 00:31:42.119 like to few tens of megabytes not more 00:31:42.120 --> 00:31:44.479 it doesn't make sense to increase it much more 00:31:44.480 --> 00:31:48.239 and if you really have major problems 00:31:48.240 --> 00:31:49.759 with Emacs being slaggy 00:31:49.760 --> 00:31:52.519 then you can increase GC count percentage 00:31:52.520 --> 00:31:55.999 to like 0.2 0.3 maybe 00:31:56.000 --> 00:31:57.679 one is probably overkill 00:31:57.680 --> 00:32:02.759 but do watch your Emacs ROM usage it may be really impacted 00:32:02.760 --> 00:32:09.719 for Emacs developers I'd like to emphasize 00:32:09.720 --> 00:32:12.439 that there is a real problem with garbage collection 00:32:12.440 --> 00:32:17.959 and nine percent of all the garbage collection 00:32:17.960 --> 00:32:22.079 data points we have correspond 00:32:22.080 --> 00:32:24.959 to really slow noticeable Emacs precision 00:32:24.960 --> 00:32:28.039 and really frequent less than 10 seconds 00:32:28.040 --> 00:32:32.319 I'd say that it's really worth 00:32:32.320 --> 00:32:35.279 increasing GC count threshold at least during startup 00:32:35.280 --> 00:32:40.159 because it really impacts the Emacs startup time 00:32:40.160 --> 00:32:41.519 making Emacs startup much faster 00:32:41.520 --> 00:32:44.799 ideally we need to reimplement 00:32:44.800 --> 00:32:48.599 the garbage collection algorithm of course it's not easy 00:32:48.600 --> 00:32:50.159 but it would be really nice 00:32:50.160 --> 00:32:56.399 and for GC count percentage defaults it's hard to say 00:32:56.400 --> 00:33:00.759 we may consider changing it but it's up to discussion 00:33:00.760 --> 00:33:03.119 and we probably need to be conservative here 00:33:03.120 --> 00:33:06.039 so we came to the end of my talk 00:33:06.040 --> 00:33:09.319 and this presentation 00:33:09.320 --> 00:33:11.839 all the data will be available publicly 00:33:11.840 --> 00:33:17.079 and you can reproduce all the statistic graphs if you wish 00:33:17.080 --> 00:33:21.920 and thank you for attention