zpmod  b19981f
High-performance Zsh module for script optimization and filesystem helpers
source_hot.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MIT */
7 // NOLINTBEGIN(misc-include-cleaner)
8 
9 #include "zpmod.mdh"
10 #include "zpmod.pro"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 typedef struct {
16  char *path;
17  long total_ms;
18  int count;
19 } hot_script_t;
20 
21 /* Comparator for qsort; parameters mandated by qsort signature. */
22 // NOLINTBEGIN(bugprone-easily-swappable-parameters)
23 static int compare_hot_scripts(const void *a, const void *b) {
24  hot_script_t *sa = (hot_script_t *)a;
25  hot_script_t *sb = (hot_script_t *)b;
26  return sb->total_ms - sa->total_ms;
27 }
28 // NOLINTEND(bugprone-easily-swappable-parameters)
29 
37 int cmd_source_hot(char *nam, char **argv) {
38  int count = 10;
39  int threshold = 0;
40  const char *zwc_file = NULL;
41 
42  while (*argv && argv[0][0] == '-') {
43  if (strcmp(argv[0], "-n") == 0) {
44  if (!argv[1]) {
45  zwarnnam(nam, "-n requires an argument");
46  return 1;
47  }
48  count = atoi(argv[1]);
49  argv += 2;
50  continue;
51  }
52  if (strcmp(argv[0], "--threshold") == 0) {
53  if (!argv[1]) {
54  zwarnnam(nam, "--threshold requires an argument");
55  return 1;
56  }
57  threshold = atoi(argv[1]);
58  argv += 2;
59  continue;
60  }
61  if (strcmp(argv[0], "--zwc") == 0) {
62  if (!argv[1]) {
63  zwarnnam(nam, "--zwc requires an argument");
64  return 1;
65  }
66  zwc_file = argv[1];
67  argv += 2;
68  continue;
69  }
70  if (strcmp(argv[0], "--") == 0) {
71  argv++;
72  break;
73  }
74  break;
75  }
76 
77  /* Feature guard: compile only if source study compiled in */
78 #ifndef ZPMOD_HAVE_SOURCE_STUDY
79  (void)count;
80  (void)threshold;
81  (void)zwc_file;
82  (void)nam;
83  (void)argv;
84  return 0;
85 #endif
86 
87  char **history = getaparam("zsh_source_history");
88  if (!history) {
89  return 0;
90  }
91 
92  int history_len = arrlen(history);
93  hot_script_t *scripts = zalloc(sizeof(hot_script_t) * history_len);
94  int script_count = 0;
95 
96  for (int i = 0; i < history_len; i++) {
97  char *line = history[i];
98  int len = (int)strlen(line);
99  char *copy = (char *)zalloc(len + 1);
100  memcpy(copy, line, len + 1);
101  char *saveptr = NULL;
102  char *path = strtok_r(copy, " ", &saveptr);
103  char *ms_str = strtok_r(NULL, " ", &saveptr);
104  if (!path || !ms_str) {
105  continue;
106  }
107 
108  long ms = atol(ms_str);
109  if (threshold > 0 && ms < threshold) {
110  continue;
111  }
112 
113  int found = 0;
114  for (int j = 0; j < script_count; j++) {
115  if (strcmp(scripts[j].path, path) == 0) {
116  scripts[j].total_ms += ms;
117  scripts[j].count++;
118  found = 1;
119  break;
120  }
121  }
122  if (!found) {
123  scripts[script_count].path = ztrdup(path);
124  scripts[script_count].total_ms = ms;
125  scripts[script_count].count = 1;
126  script_count++;
127  }
128  zfree(copy, len + 1);
129  }
130 
131  qsort(scripts, script_count, sizeof(hot_script_t), compare_hot_scripts);
132 
133  int limit = (count > 0 && count < script_count) ? count : script_count;
134 
135  for (int i = 0; i < limit; i++) {
136  char *cmd;
137  if (zwc_file) {
138  cmd = zalloc(strlen(scripts[i].path) + strlen(zwc_file) + 20);
139  sprintf(cmd, "zcompile -o %s %s", zwc_file, scripts[i].path);
140  } else {
141  cmd = zalloc(strlen(scripts[i].path) + 12);
142  sprintf(cmd, "zcompile %s", scripts[i].path);
143  }
144  execstring(cmd, 1, 0, NULL);
145  zsfree(cmd);
146  }
147 
148  for (int i = 0; i < script_count; i++) {
149  zsfree(scripts[i].path);
150  }
151  zfree(scripts, sizeof(hot_script_t) * history_len);
152 
153  return 0;
154 }
155 
156 // NOLINTEND(misc-include-cleaner)
static int compare_hot_scripts(const void *a, const void *b)
Definition: source_hot.c:23
int cmd_source_hot(char *nam, char **argv)
Implements zpmod source-hot.
Definition: source_hot.c:37
char * path
Definition: source_hot.c:16
long total_ms
Definition: source_hot.c:17
Module declaration header (mdh) for zpmod.
Prototype stub for zpmod when building out-of-tree.
void * zalloc(size_t size)
void zsfree(char *ptr)
void zfree(void *ptr, size_t size)
char ** getaparam(const char *name)
void zwarnnam(const char *, const char *,...)
char ** path
int arrlen(char **)
char * ztrdup(const char *)