// Get CPU name from /proc/cpuinfo.
char *
get_auto_cpu_name ()
{
  FILE *f;
  char buf[256];
  char *cpu_name = NULL;
  char *cpu_name_64bit = NULL;		// cpu_name of 64-bit version of CPU
  int cpu_family = -1;			// CPU family number
  int model = -1;			// CPU model number
  boolean amd = FALSE;			// AMD CPU
  boolean intel = FALSE;		// Intel CPU

  f = fopen("/proc/cpuinfo", "r");
  if (f == NULL) {
    return get_default_cpu_name("cannot read /proc/cpuinfo");
  }

  // Parse /proc/cpuinfo.
  while (fgets(buf, 256, f) != NULL) {
    // vendor_id
    if (!strncmp("vendor_id", buf, 9)) {
      if (strstr(buf, "AuthenticAMD")) {
	amd = TRUE;
      } else if (strstr(buf, "GenuineIntel")) {
	intel = TRUE;
      } else {
	return get_default_cpu_name("unsupported vendor_id in /proc/cpuinfo");
      }

    // cpu family
    } else if (!strncmp("cpu family", buf, 10)) {
      cpu_family = get_num_after_colon(buf);

    // model
    } else if (!strncmp("model\t", buf, 6) ||
	       !strncmp("model   ", buf, 8)) {
      model = get_num_after_colon(buf);

    // model name
    } else if (!strncmp("model name", buf, 10)) {
      if (strstr(buf, "Opteron")) {		// AMD
	cpu_name = "opteron";
      } else if (strstr(buf, "Athlon")) {
	if (strstr(buf, "64"))
	  cpu_name = "athlon64";
	else if (strstr(buf, "MP"))
	  cpu_name = "athlon-mp";
	else
	  cpu_name = "athlon";
      } else if (strstr(buf, "Turion")) {
	cpu_name = "turion";
      } else if (strstr(buf, "Pentium") &&	// Intel
		 strstr(buf, "4")) {
	cpu_name = "pentium4";
      } else if (strstr(buf, "Xeon")) {
	cpu_name = "xeon";
	cpu_name_64bit = "em64t";
      } else if (strstr(buf, "i7")) {
          // TODO -- need-to-date machine model.
	cpu_name = "wolfdale";
	cpu_name_64bit = "wolfdale";
      }
    } else if (strstr(buf, "GenuineIntel")) {
      intel = TRUE;
    } else if (strstr(buf, "AuthenticAMD")) {
      amd = TRUE;
    }
  }

  fclose(f);

  // If /proc/cpuinfo doesn't have a supported model name, try to derive one
  // from the family and model numbers.  If that fails, fall back to a default.
  // Bug 5785.
  // need to differentiate Core-based Xeon's
  if (intel == TRUE && (cpu_name == NULL || !strcmp(cpu_name, "xeon"))) {
    switch (cpu_family) {
      case 4:			// most 80486s
      case 5:			// Intel P5, P54C, P55C, P24T
        return "i386";

      case 6:			// P6, Core, ...
        if (model == 7 ||	// Harpertown	bug 14685
            model == 23 ||	// Wolfdale
            model == 26)	// Nehalem
          return "wolfdale";

        if (model >= 15)
          return "core";

        // Treat the rest of the P6 family as generic x86 since we don't
        // optimize for them.
        return "i386";

      case 15:		// P4
        cpu_name = "xeon";
        cpu_name_64bit = "em64t";
        break;
    }

  } else if (amd == TRUE) {
    switch (cpu_family) {
      case 4:                   // 5x86
      case 5:                   // K5, K6
      case 6:                   // K7
        return "athlon";
      case 15:
        return "opteron";       // Family 0fh (K8)
      case 16:
        return "barcelona";     // Family 10h
      case 17:
      case 18:
      case 20:
        return "opteron";       // Generic tuning for Family 11h, 12h, 14h
      case 21:
        return "bdver1";        // Family 15h
    }
  }

  if (cpu_name == NULL) {
      return get_default_cpu_name("cannot deduce a supported CPU name"
                                  " from /proc/cpuinfo");
  }

  // If cpuinfo doesn't say if CPU is 32 or 64-bit, ask the OS.
  if (cpu_name_64bit != NULL) {
    if (get_platform_abi() == ABI_64) {
      cpu_name = cpu_name_64bit;
    }
  }

  return cpu_name;
}
