Ниже мы разберёмся, насколько Р и Е ядра отличаются по скорости и почему. Америки мы не откроем — производительные ядра действительно быстрее, но более детальное понимание почему они быстрее может помочь использовать компьютер чуть более эффективно (но быстрее чем он есть, он, безусловно не станет, не ждите чудес). Это просто пятничное упражнение.

На самом деле всё началось с того, что я любопытства ради запустил мой любимый бенчмарк SHA256 (который использовался в предыдущей статье про гипер-трединг) и н��блюдал прекрасное:

>sha256b.exe
>Base Frequency 2303 MHz
9BC1B2A288B26AF7257A36277AE3816A7D4F16E89C1E7E77D0A5C48BAD62B360
8>225 MiB/s
11>225 MiB/s
2>66 MiB/s
22>71 MiB/s 
24>67 MiB/s
22>68 MiB/s
18>67 MiB/s
20>68 MiB/s
20>70 MiB/s

Бодро начавшись на Р ядрах и выдавая 225 МБ в секунду, тест довольно быстро "съезжал" на Е ядра и производительность падала втрое — до 70 МБ/с. Так быть не должно, при незагруженном процессоре однопоток должен лететь как по пустому автобану — "тапка в пол". Я погрешил на распоследнюю Windows 25H2, поставил обратно старую добрую LTSC 24H2, и проблема ушла, и я начал было писать злую статью, попутно разбираясь с 25Н2, но ларчик открывался просто — накатывая в обеденный перерыв обновления на 25Н2, я подключился к корпоративной сети, и мне прилетели не только обновления, но и политики электропитания (хоть комп и не был в домене), а админ наш, помешанный на "эко" технологиях, сумел выставить так, что любое приложение почти сразу после запуска автоматом переходило в "экономичный" режим (вот знайте, что так тоже можно). Лечится на самом деле просто — либо надо запускать с повышенным приоритетом, либо отключить powerthrottling для этого приложения через powercfg, а к версии Windows это не имело никакого отношения — что LTSC 24Н2, что свежая 25Н2 плюс минус одинаковы по производительности, но мне стало жаль выкидывать уже написанное "в помойку", так что я просто оставлю это здесь, может кому-то будет интересно.

А упражняться мы будем на ноутбуке "Lenovo ThinkPad P16 Gen 2". Сам по себе ноутбук ничего выдающегося не представляет, к покупке рекомендовать не буду по многим причинам (обзор этого поделия не входит в план статьи, от легендарного IBM ThinkPad тут лишь точечка над i). А вот процессор там довольно интересный. Как я уже писал, я начал с 25H2, даже на русский переключил:

Вот что показывает нам диспетчер задач сразу после установки:

Какая-то минимальная активность есть, но в основном загрузка по нулям и в целом примерно так и должна выглядеть "винда здорового компа" (пока она "из коробки").

Итак, мы тут видим два десятка ядер и 28 логических. ОС Windows особо не утруждает себя показом количества P и E ядер, тут (в предположении что производительные ядра гипер-тредированные) любопытному пользователю предлагается решить в уме несложную систему из двух линейных уравнений:

\begin{cases}P + E = 20 \\2P + E = 28\end{cases}

Откуда мы получаем, что у нас восемь Р ядер и двенадцать Е.

CPU-Z именно это и показывает (внизу в окошке Cores):

Здесь, кстати, любопытно не только количество ядер, но и кэш. Как мы помним из предыдущей статьи, у пар гипертредированных ядер кэш первого и второго уровня общий, поэтому у нас есть восемь раз по 48 КБ для данных и 32 КБ для инструкций для восьми Р ядер, а вот у Е ядер кеш данных поменьше, а вот инструкций — побольше и он индивидуальный для каждого Е ядра. С кэшем второго уровня тоже любопытно — у Р ядер тут просто по два мегабайта на ядро, а вот Е ядра сгруппированы в три группы по четыре ядра, и для каждой группы тут 4 мегабайта (интернет говорит, что примерно так устроены некоторые Атомы). Суммарно это даёт 16 МБ кэша второго уровня для Р ядер и 12 МБ для Е, что в менеджере задач и наблюдаем. В общем это, вероятно, лучше чем раскидать по мегабайту на ядро. Ну а кэш третьего уровня просто 30 мегабайт на всё про всё.

В том же CPU-z можно побенчмаркать эти ядра, причём Р и Е раздельно, вот что получится:

Результат в общем предсказуем, приятно видеть, что Е ядра реально независимы — двенадцать потоков дают почти двенадцатикратное ускорение, но они и медленнее чем Р, и судя по этому бенчмарку почти в два раза (784,1/430.0 = 1,823), но на самом деле всё не так плохо.

Информацию AIDA64 я оставлю под спойлером.

простыня скриншотов

AIDA P Core

AIDA E-Core

AIDA Benchmark

Леново "с завода" всегда поставит вам одну плашку, хоть на двухканальном ноуте, хоть на Xeon десктопе (а там ведь четыре канала).

Давайте для начала разберёмся, какие вообще ядра Р, а какие Е. В предыдущей статье про гипер-трединг я жёстко кодировал эти маски, но, как резонно заметили в комментариях, по фен-шую надо бы спросить у ОС о типах ядер через GetLogicalProcessorInformation(). Вот с этого домашнего задания мы и начнём наши упражнения, причём воспользовавшись ИИ, чего я совершенно не стесняюсь:

#include <windows.h>
#include <iostream>
#include <vector>
#include <bitset>
#include <iomanip> // For setw and setfill
#include <string>

using namespace std;
#define LTP_PC_SMT 0x1 // SMT (Hyperthreading) flag
#define CORE_INFO PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX

int main() {
	cout << "Hello Processor!\n";
	DWORD len = 0;
	GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &len);
	vector<uint8_t> buffer(len);
	auto info = reinterpret_cast<CORE_INFO>(buffer.data());
	int core = 0;
	if (GetLogicalProcessorInformationEx(RelationProcessorCore, info, &len)) {
		uint8_t* ptr = buffer.data();
		while (ptr < buffer.data() + len) {
			CORE_INFO lpInfoEx = reinterpret_cast<CORE_INFO>(ptr);
			DWORD_PTR mask = lpInfoEx->Processor.GroupMask[0].Mask;
			bool hasHT = lpInfoEx->Processor.Flags & LTP_PC_SMT;
			int eff = lpInfoEx->Processor.EfficiencyClass; // 0 for P, >0 for E
			string coreType = eff == 0 ? "P core" : "E core";

			bitset<28> maskBits(mask);
			cout << "Core " << setfill(' ') << setw(2) << dec << ++core 
				<< " mask: 0x" << hex << setw(7) << setfill('0') << mask 
				<< " | (b" << maskBits << ")" << " | Type: " 
				<< coreType << " | HT: " << (hasHT ? "On" : "No") << endl;
			ptr += lpInfoEx->Size;
		}
	}
	else cerr << "Failed acquiring logical processor info." << endl;
	return 0;
}

И вот результат, наши двадцать ядер, первые восемь гипертредированы:

>coreInfo.exe
Hello Processor!
Core  1 mask: 0x0000003 | (b0000000000000000000000000011) | Type: E core | HT: On
Core  2 mask: 0x000000c | (b0000000000000000000000001100) | Type: E core | HT: On
Core  3 mask: 0x0000030 | (b0000000000000000000000110000) | Type: E core | HT: On
Core  4 mask: 0x00000c0 | (b0000000000000000000011000000) | Type: E core | HT: On
Core  5 mask: 0x0000300 | (b0000000000000000001100000000) | Type: E core | HT: On
Core  6 mask: 0x0000c00 | (b0000000000000000110000000000) | Type: E core | HT: On
Core  7 mask: 0x0003000 | (b0000000000000011000000000000) | Type: E core | HT: On
Core  8 mask: 0x000c000 | (b0000000000001100000000000000) | Type: E core | HT: On
Core  9 mask: 0x0010000 | (b0000000000010000000000000000) | Type: P core | HT: No
Core 10 mask: 0x0020000 | (b0000000000100000000000000000) | Type: P core | HT: No
Core 11 mask: 0x0040000 | (b0000000001000000000000000000) | Type: P core | HT: No
Core 12 mask: 0x0080000 | (b0000000010000000000000000000) | Type: P core | HT: No
Core 13 mask: 0x0100000 | (b0000000100000000000000000000) | Type: P core | HT: No
Core 14 mask: 0x0200000 | (b0000001000000000000000000000) | Type: P core | HT: No
Core 15 mask: 0x0400000 | (b0000010000000000000000000000) | Type: P core | HT: No
Core 16 mask: 0x0800000 | (b0000100000000000000000000000) | Type: P core | HT: No
Core 17 mask: 0x1000000 | (b0001000000000000000000000000) | Type: P core | HT: No
Core 18 mask: 0x2000000 | (b0010000000000000000000000000) | Type: P core | HT: No
Core 19 mask: 0x4000000 | (b0100000000000000000000000000) | Type: P core | HT: No
Core 20 mask: 0x8000000 | (b1000000000000000000000000000) | Type: P core | HT: No

Теперь мы можем расставить буковки:

Под линуксом, кстати, порядок может быть совершенно другой.

Теперь нам нужен бенчмарк — выше был написан на ассемблере, но по ходу экспериментов ИИ набросал мне ещё один на Расте, тут всё просто, меньше тридцати строчек кода:

use std::time::{Duration, Instant};
use sha2::{Sha256, Digest};
use hex; // for hex encoding

fn main() {
    let data = vec![b'a'; 1024 * 1024]; // 1 MiB of 'a'

    // Compute the digest once and print it as hex
    let mut hasher = Sha256::new();
    hasher.update(&data);
    let result = hasher.finalize();
    println!("SHA-256 digest of 1 MiB 'a': {}", hex::encode(result));

    // Run continuous hashing speed measurement
    loop {
        let start = Instant::now();
        let mut count = 0;

        while start.elapsed() < Duration::new(1, 0) {
            let mut hasher = Sha256::new();
            hasher.update(&data);
            let _ = hasher.finalize_reset();
            count += 1;
        }
        println!("Hashing speed: {} MiB/s", count);
    }
}

Минус теста на языке высокого уровня — это то, что машинный код зависит от компилятора и библиотек, а тест на ассемблере — он всегда будет такой.

Как бы то ни было, давайте запустим оба теста SHA256 на Р и Е ядрах и для сравнения на старом Xeon и посмотрим на результат технического прогресса:

P ядро

E ядро

Xeon E5-1620 v3

Ассемблер

226 MiB/s

165 MiB/s

157 MiB/s

Раст

2352 MiB/s

2355 MiB/s

211 MiB/s

Тут, собственно, возникает два вопроса — почему тест на Расте вдесятеро быстрее теста на ассемблере и почему тест на ассемблере заметно проcедает на Е ядрах, а вот тест на Расте даже чуть быстрее?

На первый вопрос ответ прост, если посмотреть на CPU-Z выше и также просто дизассемблировать программу на Расте, сразу станет видно, что там используются аппаратные SHA инструкции, их собственно три — SHA256MSG1, SHA256MSG2 и SHA256RNDS2. Грубо говоря там, где нам на "чистом" ассемблере потребовалось десять простых инструкций, тут всего одна, вот она, сила аппаратного ускорения! И да, Раст рулит. Опять же на процессоре без аппаратной поддержки SHA вполне себе работает, корректно определяя тип процессора и переключаясь на другую ветку.

А вот чтобы ответить на второй вопрос, почему производительность Р и Е примерно одинакова на Расте и различается на Ассемблере, нам потребуется небольшой технический ликбез.

Давайте ещё раз внимательно подумаем, почему Е ядра медленнее в тестах на ассемблере и CPU-Z? Если посмотреть в спецификацию на процессор, то сразу будет видно, что в турбо бусте Р ядра в теории могут разгоняться аж до 5,3 ГГц, а вот Е ядра — только до 3,8 ГГц.

P ядра, кстати, не всегда будут работать на такой частоте, в отличие от Е ядер, если занять их все, то частота дропнется, а насколько, это AIDA показывает, мультипликаторы вот здесь:

Это очевидное различие объясняет разницу на ассемблере — 5,3 ГГц против 3,8 — примерно такая пропорция и есть, да, но почему тогда Раст не проседает? На самом деле потому, что есть и вторая причина и второе различие.

У инструкций нашего фон Неймановского процессора есть два архиважных параметра — латентность (задержка) и пропускная способность.

Латентность — это количество циклов процессора, которые необходимы ему для выполнения данной инструкции.

А пропускная способность — это максимальное количество команд одного типа, которые могут быть выполнены за один тактовый цикл, если эти команды независимы. Обычно в документации указывают обратное значение для облегчения сравнения с задержкой, то есть пропускная способность, скажем, в четыре команды будет иметь значение 0.25 (иногда этот параметр также называют задержкой выдачи).

Чем эти два параметра меньше, тем лучше. В прошлой статье мы упражнялись с IMUL, у этой инструкции на архитектуре Haswell задержка 3, а пропускная способность 1. Это значит, что чтобы перемножить два числа в регистрах, нужно три такта процессора. А пропускная способность 1 означает, что процессор может начать выполнение умножения на каждом такте процессора. Закончит-то он через три такта, а начать может именно на каждом. Если у нас идут подряд несколько независимых IMUL инструкций, то он начнёт выполнять первую, на следующем такте — вторую, затем третью и тут выполнится первая, а он начнёт следующую и так далее, то есть они выполняются "параллельно" и как бы сдвинуты по времени на один такт. Это именно то, чем мы пользовались в предыдущей статье про гипер-трединг — там параллелились умножения с двух потоков. Обратная пропускная способность может быть как больше единицы, так и меньше. Если взять примитивную ADD, которую процессору выполнять куда как проще, то у неё латентность один такт, а вот пропускная способность на Haswell 0,33 (и, забегая вперёд, 0,25 на Р ядрах). Это значит, что результат выполнения будет доступен уже на следующем такте, а вот начать выполнение подряд идущих и независимых сложений он может аж три штуки за один такт! Скорее всего вы уже поняли в чём тут дело — Р и Е ядра отличаются не только по максимальной частоте турбо буста, но также и по ТТХ отдельных инструкций.

В таблицах uops есть данные по Р и Е ядрам для архитектуры двенадцатого поколения Adler Lake (Р ядра там на архитектуре Golden Cove, а Е ядра — Gracemont), но у нас i7-13850HX, здесь Р ядра построены на архитектуре Raptor Cove, а Е ядра — те же Gracemont, но это две разные архитектуры в одном флаконе Raptor Lake (бытует мнение, что Е ядра — это "неудачные" Р ядра, но нет, это действительно две совершенно разные архитектуры, в этом и есть "гибридность" процессора). Данных по Raptor Cove в таблицы uops.info пока не завезли, но не беда, нам просто надо научиться мерить латентность и пропускную способность отдельных инструкций и всё станет ясно.

Метод измерения очень прост — для измерения латентности мы будем кормить процессор одинаковыми, причём зависимыми командами, когда результат выполнения следующей зависит от предыдущей, это не будет давать возможность им параллелиться и мы получим чистое значение латентности, просто поделив количество тактов процессора на количество обработанных инструкций. А для пропускной способности мы будет скармливать независимые команды, они как раз таки будут "параллелиться", насколько умеют и в этом случае результат деления даст нам пропускную способность. Всё просто.

Но есть нюанс. Дело в том, что посчитать количество реальных тактов ядра процессора не так-то легко, так как необходимый нам счётчик недоступен из пользовательского режима, это привилегированная инструкция RDPMC (в теории можно работать в предположении, что мы всегда крутимся на частоте турбо буста, но это не наш метод, мы ж не ищем лёгких путей). Кстати, очень часто с этим счётчиком тактов путают значение, возвращаемое инструкцией RDTSC. Так вот, этот таймер не имеет ровно никакого отношения к реальным тактам ядер, он работает постоянно независимо от частоты индивидуальных ядер и строго на одной частоте. Он будет использоваться для точного замера времени (нам ведь хочется также видеть реальную частоту индивидуального ядра). Частота RDTSC, кстати может быть определена на старых процессорах типа Haswell исключительно экспериментально и лишь на современных процессорах (к каким и наш относится) её можно запросить через CPUID. Не путайте это значение с базовой частотой, которое показывает нам Менеджер задач в Windows. Это значение берётся из BIOS, и там может быть зашито другое значение, нежели выставлено фьюзами на кристалле процессора. В конкретном данном случае, если вы промотаете статью наверх, нам показывают 2,1 ГГц, но реально таймер работает на 2,3 ГГц, и это можно получить как из CPUID:

    ; CPUID with leaf 0x16
    mov eax, 0x16
    xor ecx, ecx ; Some CPUs require ECX = 0
    cpuid ; EAX = Base; EBX = Max; ECX = Bus (MHz)

Так и просто отсчитав одну секунду используя любую доступную функцию ОС, лучше всего QueryPerformanceCounter, а не банальный и неточный Sleep(1000):

L1:
	RDTSCP
	SHL RDX, 32
	OR RAX, RDX
	SUB RAX, R13 ; Subtract previous stamp
	MOV R12, RAX ; R12 is the TSC difference
	WinABI QueryPerformanceCounter, Ticks
	MOV R11, [Ticks] ; r14 — was initial
	SUB R11, r14
	CMP R11, r15 ; Frequency, count one second
	JLE L1
Полный код
EUROASM AutoSegment=Yes, CPU=X64, SIMD=AVX2
gtcpuid PROGRAM Format=PE, Width=64, Model=Flat, IconFile=, Entry=main:
INCLUDE winscon.htm, winabi.htm, cpuext64.htm
BufEAX DB 8 * B
BufEBX DB 8 * B
BufECX DB 8 * B
BufTicks DB 32 * B
MsgEAX D "EAX = Base frequency (MHz): ",0
MsgEBX D "EBX = Max frequency (MHz): ",0
MsgECX D "ECX = Bus (reference) frequency (MHz): ",0
MsgUnsupported D "Unsupported",13,10,0
MsgTicks D "TSC Ticks/s = ",0
Ticks DB Q
Freq DB Q

main: nop
    ; CPUID with leaf 0x16
    mov eax, 0x16
    xor ecx, ecx ; Some CPUs require ECX = 0
    cpuid ; EAX = Base; EBX = Max; ECX = Bus (MHz)

    ; Check if EBX and ECX are non-zero
    test ebx, ebx
    jz .unsupported

    test ecx, ecx
    jz .unsupported

    ; Output values on the screen
	StoD BufEAX ; EAX
	StdOutput MsgEAX, BufEAX, Eol=Yes, Console=Yes
	mov eax, ebx
	StoD BufEBX
	StdOutput  MsgEBX, BufEBX, Eol=Yes, Console=Yes
	mov eax, ecx
	StoD BufECX
	StdOutput  MsgECX, BufECX, Eol=Yes, Console=Yes
    jmp .done

.unsupported:
	StdOutput MsgUnsupported, Eol=Yes, Console=Yes
.done:

	WinABI QueryPerformanceFrequency, Freq
	MOV R15, [Freq]
	WinABI QueryPerformanceCounter, Ticks
	MOV R14, [Ticks] ;
	CPUID
	RDTSC
	SHL RDX, 32
	OR RAX, RDX
	MOV R13, RAX ; R13 will hold initial Time Stamp counter value	
align 16
L1:
	RDTSCP
	SHL RDX, 32
	OR RAX, RDX
	SUB RAX, R13 ; Subtract previous stamp
	MOV R12, RAX ; R12 is the TSC difference
	WinABI QueryPerformanceCounter, Ticks
	MOV R11, [Ticks] ; r14 - was initial
	SUB R11, r14
	CMP R11, r15 ; Frequency, count one second
	JLE L1
	MOV rax, r12 ; R12 is now amount of TSC Ticks per second
	StoD BufTicks
	StdOutput  MsgTicks, BufTicks, Eol=Yes, Console=Yes


	TerminateProgram
ENDPROGRAM

Вот результат для данного процессора

>gtcpuid.exe
EAX = Base frequency (MHz): 2300
EBX = Max frequency (MHz): 5300
ECX = Bus (reference) frequency (MHz): 100
TSC Ticks/s = 2303994036 ; < Это 2304 МГц

AIDA, кстати, говоря, показывает обе частоты, вот то, что читается из BIOS/DMI, тут 2,1 ГГц (а у максимальной частоты хороший такой задел на будущее):

А вот реальная частота таймера, 2,304 ГГц, вот здесь:

И, кстати, 2304 МГц мне нравится куда как больше, чем ровно 2300 из CPUID, потому что все замеры дают что-то типа 2303994036 тиков (последние цифирки пляшут от запуска к запуску, но 230399... стоит достаточно стабильно), так что я буду пользоваться замером именно по времени.

Теперь нам потребуется ещё пара ингредиентов. Первый — это Intel Performance Counter Monitor (или коротко Intel PCM) — и это просто обязательный инструмент для постижения глубокого внутреннего мира процессора. Он обновился буквально месяц назад. Клонируйте репозиторий, аккуратно следуйте инструкции по сборке (понадобится Студия с SDK и DDK и cmake), и всё получится, но для наших нужд потребуется внести небольшое изменение в драйвер MSR.sys для того, чтобы использовать RDPMC. Чуть более подробно я писал в позапрошлой статье "Достучаться до RDPMC...".

Добавьте в msrmain.c пару функций:

VOID SetCR4PCE()
{
    ULONG_PTR cr4 = __readcr4();
    DbgPrint("PCE CR4 before setting PCE: %p\n", (PVOID)cr4);
    cr4 |= (1 << 8); // Set bit 8 (PCE)
    __writecr4(cr4);
    cr4 = __readcr4();
    DbgPrint("PCE CR4 after setting PCE: %p\n", (PVOID)cr4);
}

VOID SetCR4PCEOnAllCores()
{
    for (ULONG i = 0; i < KeQueryActiveProcessorCount(NULL); ++i) {
        GROUP_AFFINITY affinity = { 0 };
        affinity.Mask = (KAFFINITY)1 << i;
        affinity.Group = 0;

        GROUP_AFFINITY oldAffinity;
        KeSetSystemGroupAffinityThread(&affinity, &oldAffinity);

        SetCR4PCE();
        DbgPrint("PCE CR4 set for cpu %d\n", i);
        KeRevertToUserGroupAffinityThread(&oldAffinity);
    }
}

И вызов в конец DriverEntry:

    DbgPrint("Driver loaded\n");
    SetCR4PCEOnAllCores();
    DbgPrint("CR4 PCE has been set\n");

это изменение выставит бит CR4, так нужный нам для того, чтобы использовать RDPMC в нашей программе, которая само собой работает не в привилегированном режиме.

Второй ингредиент чисто технический. Дело в том, что нам потребуется выводить из кода на ассемблере дробные значения с плавающей точкой, а ЕвроАссемблер, который тут используется, умеет своими макросами StoD и StoH только в целые. Можно, конечно, написать самому, либо вкорячить сюда printf из стандартного рантайма Студии, но чтобы не продираться через дебри линковки, есть способ проще (для меня, во всяком случае) — можно позаимствовать функцию FmtOut из "эзотерического" компилятора CVI. Плюс тут в легковесности решения — нам всего-то надо слинковаться с cvirt.lib, а из всего рантайма потребуется лишь cvirte.dll. Чтобы разжиться этой библиотечкой, полностью CVI ставить не надо, достаточно бесплатного рантайма: LabWindows/CVI Runtime.

Давайте поделим пару чисел на ассемблере и напечатаем результат в консоль, тут кода всего ничего:

EUROASM AutoSegment=Yes, CPU=X64, SIMD=AVX2
cvidemo PROGRAM Format=PE, Width=64, Model=Flat, IconFile=, Entry=Start:
INCLUDE winscon.htm, winabi.htm, cpuext64.htm
FmtMsg D "%%s<%%f[p1] divided by %%f[p1] is %%f[p2]",13,10,0

Dividend DO Q 42.0
Divisor DO Q 13.0

LINK cvirt.lib
    
Start: nop
    MOVQ XMM0, [Dividend]
    MOVQ XMM1, [Divisor]
    DIVSD XMM0, XMM1
    WinABI FmtOut, FmtMsg, [Dividend], [Divisor], XMM0
    TerminateProgram
ENDPROGRAM

Результат:

>cvidemo.exe
42.0 divided by 13.0 is 3.23

Счастье есть, мир заиграл новыми красками. К тому же FmtOut потокобезопасна, чего не скажешь о макросах StoD/StdOutput.

Теперь мы во всеоружии и можем покрутить циклы.

Для оценки пропускной способности нам нужно будет выдавать последовательность независимых команд типа

	IMUL R10, R10
	IMUL R11, R11
	IMUL R12, R12
	IMUL R13, R13
	IMUL R14, R14
	IMUL R10, R10
	IMUL R11, R11
	IMUL R12, R12
	IMUL R13, R13
	IMUL R14, R14
	...

Чтоб было удобнее, заведём вот такой макрос с переменной тестовой команды, чтобы менять её только в одном месте, если мы захотим тестировать ADD, IMUL и так далее:

%TCommand %SET IMUL 
MsgTP D "Throughput & Latency Test for %TCommand",0

ThroughputBench %MACRO L
mov r9, 200_000
%L:
i %FOR  0..1000
	%TCommand r10, r10
	%TCommand r11, r11
	%TCommand r12, r12
	%TCommand r13, r13
	%TCommand r14, r14
  %ENDFOR
	dec r9
	jnz %L
%ENDMACRO

Здесь пять независимых команд повторяются тысячу раз (это даст пять тысяч инструкций), а цикл крутится двести тысяч раз, что в общей сложности даст нам миллиард инструкций. Количество повторяющихся команд в развёрнутом цикле не должно быть очень большим, все они должны поместиться в кэш инструкций, но и не очень маленьким, чтобы влияние dec/jnz (они, кстати, макро фьюзятся в одну микрооперацию) не слишком влияло на результат.

А для оценки латентности вот так, тут всё проще:

LatencyBench %MACRO L
mov r9, 200_000
%L:
i %FOR  0..5000
	%TCommand r10, r10	
  %ENDFOR
	dec r9
	jnz %L
%ENDMACRO

Здесь одна и та же команда тупо повторена пять тысяч раз, и такой же цикл.

Это называется оценка методом развёрнутого цикла. Можно сделать ещё более "универсально", но мы не ставим перед собой задачи заменить таблицы Агнера или uops.

Количество исполненных инструкций и количество затраченных на это тактов мы будем получать из RDPMC счётчиков 0x40000000 и 0x40000001, а время исполнения из классической пары RDTSC/RDTSCP.

	StartBench RDPMC, 0x40000000
ThroughputBench L1
	EndBench RDPMC, 0x40000000, Msg0, TInstr
	StartBench RDPMC, 0x40000001
ThroughputBench L2
	EndBench RDPMC, 0x40000001, Msg1, TCycl
	StartBench RDTSC, 0x0
ThroughputBench L4
	EndBench RDTSCP, 0x0, MsgT, TTSC

И для RDPMC мы ведь не забыли выключить Secure Boot, включили разрешение на загрузку неподписанных драйверов "bcdedit /set TESTSIGNING ON" и хотя бы раз запустили pcm.exe, чтобы драйвер MSR.sys разблокировал RDPMC? Если нет, то нам будет выброшено исключение 0xc0000096 — STATUS_PRIVILEGED_INSTRUCTION. Я, кстати, сделал попытку интеллигентно поставить ловушку на это исключение, но на чистом асме это ох как непросто, тут надо SEH городить, с полпинка не получилось, при этом даже просто определить возможность исполнения никак, поскольку чтение бита через __readcr4() суть та же привилегированная инструкция. Отложим на долгие зимние вечера.

Попробуем для начала и для проверки, IMUL на старичке Haswell, смотрите, какая красота (поскольку я теперь умею делать форматированный вывод прямо из асма, я упоролся и сделал таки красивую табличку):

Test | VAL  | IPC  | Instr. | Cycles | TSCnt. | ExecT. | Boost | Base | Frequency
 THR   1.00   1.00   1.00 G   1.01 G   0.98 G   0.28 s   x1.03   3.49   3.58 GHz
 LAT   3.00   0.33   1.01 G   3.01 G   2.93 G   0.84 s   x1.03   3.49   3.59 GHz

Легенда: THR — это пропускная способность и она единица (колонка Value — это значение). LAT — это латентность и она три такта. IPC — это количество инструкция на такт. Instr — это собственно количество инструкций и оно миллиард в обоих тестах (при тестировании латентности гипер-трединг присунул нам немного инструкций в простаивающий конвейер), а Cycles — это количество тактов ядра, отсюда и такие значения IPC (это инструкции, делённые на циклы). TSCnt — это количество тиков таймера, который для этого процессора 3,5 ГГц. ExecT — это время выполнения миллиарда инструкций (в секундах), Boost — это насколько поднялась базовая частота, а Frequency — это истинная реальная частота ядра, до которой он дотурбобустился. Как в аптеке, я б сказал.

Ну давайте вернёмся к нашим ядрам на i7-13850HX:

Вот P ядро, ровно тот же тест:

Test | VAL  | IPC  | Instr. | Cycles | TSCnt. | ExecT. | Boost | Base | Frequency
 THR   1.00   1.00   1.00 G   1.01 G   0.46 G   0.20 s   x2.20   2.30   5.07 GHz
 LAT   2.99   0.33   1.01 G   3.01 G   1.38 G   0.60 s   x2.18   2.30   5.03 GHz

Ровно та же латентность и пропускная способность, только на пяти гигагерцах

А вот Е ядро:

Test | VAL  | IPC  | Instr. | Cycles | TSCnt. | ExecT. | Boost | Base | Frequency
 THR   1.00   1.00   1.00 G   1.00 G   0.61 G   0.27 s   x1.63   2.30   3.76 GHz
 LAT   5.00   0.20   1.00 G   5.01 G   3.09 G   1.34 s   x1.62   2.30   3.74 GHz

Здесь турбо буст заметно пожиже, а латентность аж пять тактов. И оцените время исполнения миллиарда команд — там, где P ядру требовалось всего 0.6 секунды, а старичку Haswell 0.84 здесь уже 1.34 секунды! Это практически вдвое медленнее, как и показывает CPU-Z.

А ну-ка, сложение ADD:

Р ядро, молотит как из пулемёта, оцените пропускную способность 0,25, это четыре команды в параллель:

Test | VAL  | IPC  | Instr. | Cycles | TSCnt. | ExecT. | Boost | Base | Frequency
 THR   0.24   4.19   1.00 G   0.24 G   0.11 G   0.05 s   x2.19   2.30   5.04 GHz
 LAT   1.00   1.00   1.00 G   1.00 G   0.46 G   0.20 s   x2.18   2.30   5.03 GHz

А вот Е ядро, тут всё погрустнее:

Test | VAL  | IPC  | Instr. | Cycles | TSCnt. | ExecT. | Boost | Base | Frequency
 THR   0.32   3.14   1.00 G   0.32 G   0.19 G   0.08 s   x1.64   2.30   3.78 GHz
 LAT   1.00   1.00   1.00 G   1.00 G   0.61 G   0.27 s   x1.63   2.30   3.76 GHz

Ну и старичок Haswell

Test | VAL  | IPC  | Instr. | Cycles | TSCnt. | ExecT. | Boost | Base | Frequency
 THR   0.33   3.01   1.00 G   0.33 G   0.32 G   0.09 s   x1.03   3.49   3.59 GHz
 LAT   1.00   1.00   1.00 G   1.01 G   0.98 G   0.28 s   x1.03   3.49   3.59 GHz

То есть "в среднем по больнице" производительность Е ядер на этом процессоре примерно сравнима с Haswell десятилетней давности. Но при этом не надо забывать, что тут их аж двенадцать штук.

Теперь можно погонять SHA256 инструкции и тут всё поинтереснее, SHA256MSG1 xmm, xmm:

Р ядро, он очень старается, но получается не очень:

Test | VAL  | IPC  | Instr. | Cycles | TSCnt. | ExecT. | Boost | Base | Frequency
 THR   3.96   0.25   1.02 G   4.03 G   1.85 G   0.80 s   x2.18   2.30   5.02 GHz
 LAT   5.43   0.18   1.01 G   5.49 G   2.51 G   1.09 s   x2.19   2.30   5.04 GHz

А вот Е ядро

 THR   1.00   1.00   1.00 G   1.00 G   0.62 G   0.27 s   x1.63   2.30   3.75 GHz
 LAT   3.01   0.33   1.00 G   3.01 G   1.85 G   0.80 s   x1.63   2.30   3.75 GHz

Для этого ядра SHA256MSG1 — это раз плюнуть, всё равно что умножение двух регистров, здесь и пропускная способность вчетверо больше и латентность ниже, и по времени выполнения Е ядра обгоняют Р, даже несмотря на то, что работают на значительно меньшей частоте.

А вот инструкция SHA256RNDS2:

Е ядро, тут хорошая пропускная способность:

Test | VAL  | IPC  | Instr. | Cycles | TSCnt. | ExecT. | Boost | Base | Frequency
 THR   1.00   1.00   1.00 G   1.00 G   0.62 G   0.27 s   x1.63   2.30   3.76 GHz
 LAT   4.01   0.25   1.00 G   4.02 G   2.48 G   1.08 s   x1.62   2.30   3.74 GHz

И Р ядро, здесь пропускная способность заметно хуже, а вот латентность одинакова.

Test | VAL  | IPC  | Instr. | Cycles | TSCnt. | ExecT. | Boost | Base | Frequency
 THR   2.99   0.33   1.01 G   3.02 G   1.39 G   0.60 s   x2.17   2.30   5.00 GHz
 LAT   3.97   0.25   1.01 G   4.02 G   1.85 G   0.80 s   x2.17   2.30   5.00 GHz

Хотя прогресс на месте не стоит, у Golden Cove (что из предыдущего поколения Alder Lake) латентность была 6 тактов, а теперь у Raptor Cove стала четыре.

Вот вам и ответ, почему скорость теста на Расте примерно одинакова — частота-то ниже, зато лучше латентность и пропускная способность, оно взаимно нивелируется, "так на так" и выходит. Ну а Хасвеллу таких чудо команд не завезли.

Из всего этого можно сделать вывод, что общее замедление на Е ядрах спрогнозировать практически невозможно, это очень сильно зависит от машинного кода, можно и двукратное пенальти легко огрести, а можно и вровень с Р ядрами.

Память/Кэш

Тест был бы неполон без теста памяти. Ведь каждый программист должен хоть раз написать тудушник/заметочник, просмотрщик картинок и тест, показывающий размер кэшей.

Будем читать гигабайт памяти, но вначале из 16 килобайт (ну то есть мы будем читать 16384 одних и тех же байт 65536 раз), затем из 32 (32768 байт 32768 раз), и так далее, каждый раз когда мы будем забираться во всё более и более старшие адреса оно будет становиться медленнее и медленнее, а мы будем считать, сколько таких циклов мы успеем сделать за одну секунду.

Побайтово, как четверть века назад, память уже давно никто не читает, один из самых быстрых способов это воспользоваться серией команд VMOVDQA (если вы заглянете в потрошки memcpy, то увидите, что там копирование памяти примерно так и устроено), в предположении что указатель в RDX, мы будем читать по 32 байта за раз, каждые две команды будут выбирать всю кэш-линию в 64 байта (массив для чтения в памяти выровнен на границу страницы, само собой разумеется), вот так:

	vmovdqa ymm1, [rdx]
	vmovdqa ymm2, [rdx+32]
	vmovdqa ymm3, [rdx+64]
	vmovdqa ymm4, [rdx+96]

Вот результат и для сравнения пара Xeon процессоров (три первых строчки показывают размер кэшей для справки), хорошо видно ступенчатое падение производительности когда мы переходим на следующий уровень кэша:

Size

Xeon E5-1620 v3

Xeon w5-2445

i7-13850HX P

i7-13850HX E

L1 D

32KB

48KB

48 KB

32KB

L2

256 KB

2 MB

2 MB

4 MB

L3

10 MB

26,25 MB

30 MB

30 MB

Результат

16 KB

199 GB/s

246 GB/s

355 GB/s

111 GB/s

32 KB

198 GB/s

244 GB/s

355 GB/s

110 GB/s

64 KB

89 GB/s

157 GB/s

198 GB/s

81 GB/s

128 KB

86 GB/s

157 GB/s

199 GB/s

81 GB/s

256 KB

74 GB/s (L2)

156 GB/s

199 GB/s

83 GB/s

512 KB

37 GB/s

155 GB/s

196 GB/s

84 GB/s

1 MB

37 GB/s

152 GB/s

192 GB/s

84 GB/s

2 MB

37 GB/s

93 GB/s (L2)

144 GB/s (L2)

84 GB/s

4 MB

37 GB/s

55 GB/s

71 GB/s

56 GB/s (L2)

8 MB

35 GB/s

54 GB/s

70 GB/s

33 GB/s

16 MB

16 GB/s

46 GB/s

62 GB/s

30 GB/s

32 MB

16 GB/s

26 GB/s

40 GB/s (L3)

14 GB/s (L3)

64 MB

16 GB/s

20 GB/s

26 GB/s

9 GB/s

128 MB

16 GB/s

17 GB/s

23 GB/s

9 GB/s

256 MB

16 GB/s

17 GB/s

22 GB/s

9 GB/s

512 MB

16 GB/s

16 GB/s

21 GB/s

9 GB/s

1 GB

16 GB/s

16 GB/s

22 GB/s

9 GB/s

По чтению памяти производительность Е ядер чуть ли не вдвое-трое хуже чем Р и это связано как раз с командами VMOVDQA — их пропускная способность на Р ядре 0,33, а на Е ядре 0,67, вот откуда основная разница.

Ну и не следует забывать, что кэш второго уровня сгруппирован в три группы по четыре ядра, так что если читать одну и ту же область памяти с двух потоков, то лучше это делать на соседних ядрах из одной группы, иначе нам будет мешать когерентность кэша а вот если читать/писать разные области памяти, то лучше это делать с разных групп, чтобы у каждого потока был собственный кэш — так можно избежать "загрязнения" кэша. В принципе это можно показать практически, но тут немного мешает раздельный кэш первого уровня. Но, скорее всего, если вы начали оптимизировать в этом месте, то всё, что было написано выше вам и так не нужно. Ну и опять же общая низкая пропускная способность памяти на Е ядрах таки предполагает расположение интенсивных операций с памятью на Р ядрах, а не на Е.

Тест экономичности

Е ядра позиционируются как экономичные. Я, некоторое время подумав, решил сделать вот какой тест "экономичности". Я отключу блок питания и запущу расчёт SHA-256 вначале на всех ядрах, то есть в 28 потоков, затем только на восьми производительных ядрах в 16 потоков, а потом на 12 экономичных и посмотрим, сколько мегабайт входных данных он сможет обработать на одном заряде аккумулятора (я буду смотреть до 10% остатка заряда) и с какой скоростью будет идти расчёт. Напомню, ��то однопоток выдавал примерно 2350 МБ/с что на Р что на Е ядрах. Между тестами аккумулятор будет заряжаться до 100%, это занимает примерно пару часов.

Тест

Время работы на одном заряде

МБ/с

МБ суммарно

28 потоков на всех

13:53 — 14:50 — 57 мин

34 150

116 796 103

16 потоков на Р ядрах

16:49 — 17:50 — 1ч 1 мин

18 870

69 066 256

12 потоков на Е ядрах

21:21 — 22:38 — 1ч 17 мин

26 593

122 863 614

Суммарно мы смогли посчитать только на Е ядрах даже больше чем на всех, это связано с тем, что на максималках процессор постоянно троттлился, потому что он не может отдавать такую производительность чисто на аккумуляторе. Если подключить блок питания (а он, на секундочку, 230 Ватт и отдаёт почти двенадцать ампер), то тест начнётся примерно на 50000 МБ/с и через некоторое время снизится до 45000 МБ/с из-за термического троттлинга. Но в общем и целом неплохой результат. Код теста (как и всего остального, что было выше в статье) в репозитории pecores-habr.

Сейчас вот читаю про то, что в Panther Lake Интел вроде бы хочет отказаться от гипер-трединга, и в принципе с такими Е ядрами уже можно, но мне вот будет немножко жаль этой технологии, и хотя латентность и пропускная способность тоже потихоньку улучшаются, но кто же будет заполнять время от времени простаивающие конвейеры?

Вот, собственно и всё, чем хотелось бы поделиться в этот пятничный вечер. Всем хороших выходных и быстрого кода!

Комментарии (26)


  1. MountainGoat
    17.10.2025 16:59

    Передаётся привет всей секте Сидетелей на Win10, которая не всегда грамотно распоряжается P и E ядрами и может держать ваш рабочий процесс на E ядрах.


    1. AndreyDmitriev Автор
      17.10.2025 16:59

      Идея проверить десятку меня не посетила, но оно в общем и не особо актуально, учитывая что пару дней назад поддержка закончилась. А на тех 11, что я тестировал, неожиданных перескоков на Е ядра я не заметил (если не включать эко режим, само собой). Можно, конечно, нагружать ядра постепенно и смотреть, как они будут задействоваться, но это больше вопрос к планировщику потоков.


      1. MountainGoat
        17.10.2025 16:59

        Вот именно планировщик в 11 и обновили несколько раз, чтобы он не выкидывал фортелей, сначала ради скукоженных кокосиков Intel, потом для барских двухчиплетных Zen5. я отлично помню как всякие ютуберы намеряли прирост ФПС в играх, упирающихся в процессоры. Обычно 5-8% но где-то и по 20%.


    1. dky
      17.10.2025 16:59

      Но ведь в статье на энергоэффективные ядра тест перекинула именно Win11 и автор написал почему. Настройки энергосбережения видимо могут меняться от патча к патчу, у меня лично на Win10 настройка "Heterogeneous policy in effect" по умолчанию установлена в "4" и с ней все фоновые потоки крутятся на энергоэффективных ядрах, а производительные вступают в силу при запуске например игрушек, причем если производительности хватает, то видно что винда пытается не использовать гипертрединг, а если уже не хватает, тогда в ход идут и гипертрединг и энергоэффективные ядра, такой результат лично меня полностью устраивает. В моей Win11 (установлена для тестов) указанный выше параметр по умолчанию установлен в "0" и винда со старта зачем-то использует все ядра. Но всегда можно в Win10 установить параметр в "0" или в Win11 установить в "4" и операционки в этом плане поменяются местами. Дополнительное влияние оказывают параметры "Heterogeneous thread scheduling policy" и "Heterogeneous short running thread scheduling policy", можно настроить работу под себя и в Win10 и в Win11.


      1. AndreyDmitriev Автор
        17.10.2025 16:59

        В принципе то, как Win11 работает сразу после установки - почти норм, я в настройках электропитания пару изменений сделал, но не более. Хотя под рукой желательно иметь небольшой, но проверенный бенчмарк и время от времени, после больших обновлений проверять производительность. Планировщик потоков и тонкие настройки тоже можно поисследовать, но это отдельная тема.


        1. eLeFury
          17.10.2025 16:59

          Можете поделиться настройками и логикой? Есть у меня проблема с игнорированием е-ядер в эко-режиме (!), изучаю возможные решения.


          1. AndreyDmitriev Автор
            17.10.2025 16:59

            У меня только немецкие скриншоты под рукой, но в другом языке эти опции ровно на тех же местах, и я правда ничего специального не подкручивал, только пара мелочей:

            Вот тут я выставил наилучшую производительность (была "сбалансированная или типа того), по-немецки это "Beste Leistung":

            И сделал Ultimate план (по умолчанию был только сбалансированный):

            где минимальную производительность вывел в 100%:

            (но это не значит, что он постоянно будет на максимальной частоте молотить), ну и там таймауты экрана настроил и засыпание вообще отключил.

            Что касается "эффективного режима" для приложения, то если его включить при настройках выше, то производительность упадёт, но процесс останется на Р ядрах, а чтобы он перепрыгнул на Е ядра надо также включить экономичный режим в настройках (Beste Energieeffizienz - это "наилучшая экономичность"):

            На гифке выше тест SHA256 показывает номер ядра и вначале работает на Р ядрах на 220+ МБ/с, затем я включаю "эффективный режим" в таск менеждере, он тут же снижает производительность до 64 МБ/с, но он лишь изредка запрыгивает на Е (которые 16...27), а вот если я до кучи включаю экономичный режим в настройках, то вот тогда он начинает работать преимущественно на Е. Если выключить экономичный режим приложения, но оставить в настройках, то будет что-то среднее, но опять же на Е ядрах.

            Вообще что касается планировщика потоков, то у гибридного процессора с Р и Е ядрами есть такая фишка как Intel Thread Director, который вроде как должен помогать операционке распеределять потоки по ядрам наиболее оптимальным образом, но это было несколько за рамками исследования.


  1. Tzimie
    17.10.2025 16:59

    А вот интересно, ему эту хрень на сервере иметь. CPU вообще непонятно что показывать будет (и сейчас из-за HT процент 50 CPU означает что текстуры осталось мало, но будет ещё хуже).

    А ещё есть облака, шутливые соседи, и видимо рандом какой виртуалке какие ядра достались?


  1. goldexer
    17.10.2025 16:59

    Ну, тем не менее, более новый и быстрый процессор на 11 винде показал сильные просадки в Elden Ring, как выяснило комьюнити, именно из-за Е-ядер и что-нибудь сделать с этим можно либо получив бан (ибо никакого вмешательства античит не терпит), либо играя не в сети, либо вернуться на старенький Райзен, который тем не менее держит почти вполовину больший и гораздо более стабильный FPS. Я это всё к чему: пока мы меряем хэши и с умным видом киваем в сторону архитектур, простой человек покупает вдвое более дорогой ноутбук, по всем тестам вроде бы вдвое более производительный и получает вдвое худший опыт в своих задачах. Там софт, тут драйвера, сям электропитание - и вот так совпало, что очень многое работает хуже. Весьма печально, так быть не должно. А обывателю теперь будет сложно доказать, что мол «они там все починили, покупай Intel не бойся»


    1. AndreyDmitriev Автор
      17.10.2025 16:59

      С этим я, кстати, совершенно согласен. Наличие Е ядер вносит дополнительную степень сложности (ещё и впридачу к гипер-тредингу на Р ядрах), и это приводит к тому, что для получения полной производительности и ОС и исполняемое приложение должны совместно учитывать эти особенности. Раньше, кстати, в виндовс были кнопки типа "высокая/максимальная производительность", теперь их выпилили, точнее спрятали. Ну и у любого наблюдаемого падения производительности обычно есть рациональная причина, просто народ ленится досконально и кропотливо разбираться, равно как и программировать максимально эффективно, весь мир идёт по пути наименьшего сопротивления, здесь, сейчас и в продакшен - спросил число потоков, запустил их все скопом, дальше пусть ОС разруливает. Так то в Е ядрах ничего особенного нет, но, к примеру, если мне потребуется, скажем, алгоритм быстрой мультипоточной свёртки по картинке лошадиных размеров вот на таком проце, то теперь я отдам на Е ядра меньшие кусочки, чтобы все потоки с Р и Е ядер пришли к финишу примерно в одно время.


  1. Nizametdinov
    17.10.2025 16:59

    Можно упростить тесты энергоэффективности - в hwinfo программе есть все значения мгновенные по энергопотреблению процессора (целиком, блок переферии, ядра и.т.д.). Запускаете тест, смотрите потребление, высчитываете производительность на Вт. И не надо ждать и переферии типа монитора и ссд не будет влиять.

    Вообще имхо е ядра как бы их не хаяли - это прям прорыв Интел, сам использую n100 под домашний минисервер, все же производительность хасвела в 6вт потребления это круто.


    1. kevinv
      17.10.2025 16:59

      При полной нагрузке и частотах около 2.9 ГГц это ближе к 20Вт (https://www.reddit.com/r/BeelinkOfficial/comments/1b6611f/the_performance_of_intel_processor_alder_laken100/). На фоне старых выглядит неплохо, на фоне Zen3-5/M1-M4 уже совсем не впечатляет и по абсолютным результатам, и по perf/w.


      1. Nizametdinov
        17.10.2025 16:59

        perf/w

        А если ещё добавить стоимость...? ))


        1. kevinv
          17.10.2025 16:59

          Если нет цели собрать самое дешёвое устройство, то всё равно невыгодно. По нашим ценам на miniPC - minisForum UN100P 200Euro, UM560 XT (R5 5600H) 300 Euro, UM750L (R5 7545U) 330Euro. В 1.5-2 раза быстрее в однопотоке, в 2.5-4 раза в многопотоке, в зависимости от нагрузки и в 4-5 раз быстрее GPU.

          N100 у меня есть в NAS от UGreen, но это готовое устройство. В самосборе бы вряд ли на нём стал собирать, всё же довольно нетороплив, если хоть какую то нагрузку создавать.


      1. Loco2k
        17.10.2025 16:59

        Не знаю про билинк, но китайские производители на n100 сильно халтурят в плане режимов энергосбережения. Потолок n100 15вт с нагруженным видео ядром, насколько я знаю


        1. kevinv
          17.10.2025 16:59

          Power Limit это конфигурируемый параметр. Там есть тесты на 10, 15 и 20. E ядра Alder Lake это скорее про экономию места, чем про энергоэффективность.


  1. kevinv
    17.10.2025 16:59

    Подходы Apple (больше производительных ядер, меньше энергоэффективных) и AMD (одинаковые архитектурно ядра с разной плотностью и частотой) мне понравились куда больше. С зоопарком Intel куча проблем, когда есть одинаково приоритетные задачи в разных процессах (в виртуалках/контейнерах). По бенчмаркам всё красиво, а на деле получается совсем не то, что ожидается.

    Кадавры вроде 2P+8E работают совсем уж специфично, без ручного распределения потоков окно с видеоконференцией будет висеть на P, а фоновая сборка тупить на Е (и тупить очень сильно).


  1. edo1h
    17.10.2025 16:59

    мне прилетели не только обновления, но и политики электропитания (хоть комп и не был в домене)

    Это как так?!?


    1. AndreyDmitriev Автор
      17.10.2025 16:59

      Секьюрити, а точнее Большой брат, который бдит мою безопасность на работе, делает это фактически посредством MITM, с подменой сертификатов, мониторингом трафика и всё такое. Я, лазая по установкам уже потом заметил, что в разделе электропитания вверху висело сообщение "установки контролируются администратором", и это на чистой ОС с локальной учёткой, вообще нигде не регистрированной, но после обновлений. У коллеги ноут, что в домене, ровно также "задушен". Я, может, на досуге повторю эксперимент с чистого листа.


      1. edo1h
        17.10.2025 16:59

        фактически посредством MITM

        это вызывает ещё больше вопросов


  1. AlexeyK77
    17.10.2025 16:59

    В биосе (у нотиков леново точно это есть) можно отклчить гипертрединг. Интересно было бы посмотреть как это повиляиет на результаты тестов, особенно в тест от батареи. Пишут, что отключение гипертрединга здорово увеличивает автономность в обычной бытовой нагрзуке, но каких-то конкретных измерений я не видел. Что думаете?


    1. AndreyDmitriev Автор
      17.10.2025 16:59

      Думаю, что повлияет несильно, я когда тесты делал, смотрел потребление с нагрузкой НТ ядер и без, там разница гомеопатическая была, впрочем в Биос я эти ядра не отключал. Это можно проверить, время работы должно быть чуть больше (я запущу 8 потоков, а не 16), но несильно.