Commit 8da13fda authored by Mark Fasheh's avatar Mark Fasheh

Detect whether a cpu has hypthreading

My hyperthreaded systems show a drastic performance drop during the
find_dupes stage when we use the # of processors reported by the system.
sysconf(_SC_NPROCESSORS_ONLN) can only give us the count of logical
processors, and there's no 'standard' way that I can see to get the physical
count.

So instead we parse /proc/cpuinfo and look for an Intel CPU. If we find
that, we check the flags field for 'ht'.
Signed-off-by: 's avatarMark Fasheh <mfasheh@suse.de>
parent 350404c1
......@@ -74,6 +74,8 @@ static enum {
H_UPDATE,
} use_hashfile = H_UPDATE;
static char *serialize_fname = NULL;
static unsigned int nr_logical_cpus;
static unsigned int nr_physical_cpus;
unsigned int io_threads;
int do_lookup_extents = 0;
int fiemap_during_dedupe = 1;
......@@ -653,19 +655,16 @@ int main(int argc, char **argv)
init_results_tree(&res);
init_hash_tree(&dups_tree);
/* Parse options might change this so set a default here */
#if GLIB_CHECK_VERSION(2,36,0)
io_threads = g_get_num_processors();
#else
io_threads = sysconf(_SC_NPROCESSORS_ONLN);
#endif
ret = parse_options(argc, argv, &filelist_idx);
if (ret || version_only) {
usage(argv[0]);
return (version_only || help_option) ? 0 : EINVAL;
}
get_num_cpus(&nr_physical_cpus, &nr_logical_cpus);
if (!io_threads)
io_threads = nr_logical_cpus;
if (fdupes_mode)
return add_files_from_stdin(1);
......
......@@ -28,6 +28,9 @@
#include <execinfo.h>
#endif
#include <sys/time.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include "debug.h"
#include "util.h"
......@@ -167,3 +170,99 @@ int num_digits(unsigned long long num)
}
return digits;
}
#define VENDOR_KEY "vendor_id"
#define VENDOR_VAL "GenuineIntel"
#define FLAGS_KEY "flags"
#define HT_FLAG "ht"
#define CPUINFO_DELIM ':'
#define FLAGS_DELIM ' '
/* Checks /proc/cpuinfo for an Intel CPU with hyperthreading. */
static int detect_ht(void)
{
FILE *fp;
int err = 0;
int ret = 0;
char line[LINE_MAX + 1];
char *c, *val, *key, *flag;
int check_vendor = 1;
fp = fopen("/proc/cpuinfo", "r");
if (fp == NULL) {
err = errno;
goto out;
}
while (fgets(line, LINE_MAX + 1, fp) != NULL) {
c = strchr(line, CPUINFO_DELIM);
if (!c)
continue;
key = line;
val = c + 1;/* line is \0 delimited so this should be safe */
if (*val == '\0') /* No value... */
continue;
/* Strip trailing whitespace from the key. */
do {
*c = '\0';
c--;
} while (c > key && !isalnum(*c));
/* Strip leading and trailing whitespace from val. */
while (isspace(*val) && *val != '\0')
val++;
c = &val[strlen(val) - 1];
while (isspace(*c) && c >= val) {
*c = '\0';
c--;
}
// printf("key: \"%s\" val: \"%s\"\n", key, val);
if (check_vendor && !strcmp(key, VENDOR_KEY)) {
/* No intel == no ht */
if (strcmp(val, VENDOR_VAL))
goto out_close;
check_vendor = 0;
} else if (!strcmp(key, FLAGS_KEY)) {
for (flag = val; flag && *flag; flag = c) {
c = strchr(flag, FLAGS_DELIM);
if (c) {
*c = '\0';
c++;
}
// printf("\"flag: %s\"\n", flag);
if (!strcmp(flag, HT_FLAG))
return 1;
}
/* No 'ht' in flags? We're done. */
goto out_close;
}
}
if (ferror(fp))
err = errno;
out_close:
fclose(fp);
out:
if (err)
fprintf(stderr,
"Error %d (\"%s\") while checking /proc/cpuinfo for "
"hyperthreading -- will assume ht is off.\n", err,
strerror(err));
return ret;
}
void get_num_cpus(unsigned int *nr_phys, unsigned int *nr_log)
{
int ht;
*nr_phys = *nr_log = sysconf(_SC_NPROCESSORS_ONLN);
ht = detect_ht();
if (ht && *nr_phys >= 2)
*nr_phys /= 2;
dprintf("Detected %u logical and %u physical cpus (ht is %s).\n",
*nr_log, *nr_phys, ht ? "on" : "off");
}
......@@ -51,4 +51,6 @@ void record_end_print(struct elapsed_time *e);
int num_digits(unsigned long long num);
void get_num_cpus(unsigned int *nr_phys, unsigned int *nr_log);
#endif /* __UTIL_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment