detecting hyperthreading

Alan Somers asomers at freebsd.org
Tue Mar 10 16:07:21 UTC 2015


On Tue, Mar 10, 2015 at 10:02 AM, Freddie Cash <fjwcash at gmail.com> wrote:
> On Tue, Mar 10, 2015 at 8:56 AM, Pokala, Ravi <rpokala at panasas.com> wrote:
>
>> -----Original Message-----
>> From: "lokadamus at gmx.de" <lokadamus at gmx.de>
>> Date: 2015-03-10, Tuesday at 08:52
>> To: Ravi Pokala <rpokala at panasas.com>, Rui Paulo <rpaulo at me.com>
>> Cc: "freebsd-hackers at freebsd.org" <freebsd-hackers at freebsd.org>
>> Subject: Re: detecting hyperthreading
>>
>> >Have you look at dmesg?
>> >My system is a P4 with HTT.
>> >dmesg |more
>> [...]
>> >CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz (3000.00-MHz 686-class CPU)
>> >  Origin = "GenuineIntel"  Id = 0xf29  Family = 0xf  Model = 0x2
>> >Stepping = 9
>> >
>> >Features=0xbfebfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,M
>> >CA,CMOV,PAT,PSE36,CLFLUSH,DTS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE>
>> >  Features2=0x4400<CNXT-ID,xTPR>
>>
>> Of course. :-)
>>
>> But there are two problems:
>>
>> (1) That just tells me HTT is supported by the CPU, not that if kernel is
>> using it.
>> (2) It's difficult to parse.
>>
>> Of the two, (1) is the bigger concern for my use-case.
>>
>
> 6 lines or so below the Features line shows the kernel loading "cpu0
> (BSP)", and then "cpu1 (AP/HT)".
>
> Compare that to a system without HTT, where any extra cpus only show "(AP)".
>
> It's not perfect, but one could grep through /var/run/dmesg.boot looking
> for "cpu" lines and checking for "(AP)" or "(AP/HT)".
>
> --
> Freddie Cash
> fjwcash at gmail.com

I always look at "sysctl kern.sched.topology_spec" to tell if
hyperthreading is enabled.  It's overkill, but it works.  Here's some
Ruby code that can parse it:

require 'rexml/document'

  # Parses the output of "sysctl kern.sched.topology_spec and returns a triple
  # of [number of sockets, cores/socket, threads/core]
  def _parse_topo(topology)
    cpu_xpath = "groups/group/children/group/cpu"
    xmldoc = REXML::Document.new(topology)
    _punt_topo(topology) unless xmldoc.get_elements("groups/group").count == 1
    sockets = xmldoc.get_elements("groups/group/children/group").count
    all_cores_per_socket = Set.new([])
    all_threads_per_core = Set.new([])
    xmldoc.get_elements("groups/group/children/group").each do |group2|
      cores = 0
      children = group2.get_elements("children/group")
      if children.empty?
        # No hyperthreading
        cpu_entities = group2.get_elements("cpu")
        _punt_topo(topology) unless cpu_entities.count == 1
        core_count = cpu_entities.first.attribute("count").value
        cores += core_count.to_i
      else
        children.each do |group3|
          if group3.get_elements("flags/flag[@name='SMT']").empty? && \
             group3.get_elements("flags/flag[@name='HTT']").empty? && \
             group3.get_elements("flags/flag[@name='THREAD']").empty?
          else
            # This cpu group represents a single hyperthreaded core
            cores += 1
            cpu_entities = group3.get_elements("cpu")
            _punt_topo(topology) unless cpu_entities.count == 1
            core_count = cpu_entities.first.attribute("count").value
            all_threads_per_core.add(core_count.to_i)
          end
        end
      end
      all_cores_per_socket.add cores
    end

    if all_cores_per_socket.size > 1
      cores_per_socket = "mixed"
    else
      cores_per_socket = all_cores_per_socket.first.to_i
    end

    if all_threads_per_core.size > 1
      threads_per_core = "mixed"
    elsif all_threads_per_core.size == 0
      # No SMT sections means no hyperthreading
      threads_per_core = 1
    else
      threads_per_core = all_threads_per_core.first.to_i
    end
    [sockets, cores_per_socket, threads_per_core]
  end

    # Helper method for _parse_topo
  def _punt_topo(topo)
    STDERR.puts topology
    raise IOError.new "Output of kern.sched.topology is not understood"
  end

-Alan


More information about the freebsd-hackers mailing list