@@ -145,7 +145,18 @@ DECLARE @StringToExecute NVARCHAR(MAX),
145145 @get_thread_time_ms NVARCHAR (MAX ) = N ' ' ,
146146 @thread_time_ms FLOAT = 0 ,
147147 @logical_processors INT = 0 ,
148- @max_worker_threads INT = 0 ;
148+ @max_worker_threads INT = 0 ,
149+ @is_windows_operating_system BIT = 1 ;
150+
151+ IF EXISTS
152+ (
153+ SELECT 1
154+ FROM sys .all_objects
155+ WHERE name = ' dm_os_host_info'
156+ )
157+ BEGIN
158+ SELECT @is_windows_operating_system = CASE WHEN host_platform = ' Windows' THEN 1 ELSE 0 END FROM sys .dm_os_host_info ;
159+ END ;
149160
150161/* Sanitize our inputs */
151162SELECT
@@ -2399,19 +2410,28 @@ If one of them is a lead blocker, consider killing that query.'' AS HowToStopit,
23992410 RAISERROR (' Running CheckID 24' ,10 ,1 ) WITH NOWAIT ;
24002411 END
24012412
2413+ /* Traditionally, we use 100 - SystemIdle here.
2414+ However, SystemIdle is always 0 on Linux.
2415+ So if we are on Linux, we use ProcessUtilization instead.
2416+ This is the approach found in
2417+ https://techcommunity.microsoft.com/blog/sqlserver/sql-server-cpu-usage-available-in-sys-dm-os-ring-buffers-dmv-starting-sql-server/825361 */
24022418 INSERT INTO #BlitzFirstResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL )
2403- SELECT 24 , 50 , ' Server Performance' , ' High CPU Utilization' , CAST (100 - SystemIdle AS NVARCHAR (20 )) + N ' %.' , 100 - SystemIdle, ' https://www.brentozar.com/go/cpu'
2419+ SELECT 24 , 50 , ' Server Performance' , ' High CPU Utilization' , CAST (CpuUsage AS NVARCHAR (20 )) + N ' %.' , CpuUsage, ' https://www.brentozar.com/go/cpu'
2420+ FROM (
2421+ SELECT CASE WHEN @is_windows_operating_system = 1 THEN 100 - SystemIdle ELSE ProcessUtilization END AS CpuUsage
24042422 FROM (
24052423 SELECT record,
2406- record .value (' (./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]' , ' int' ) AS SystemIdle
2424+ record .value (' (./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]' , ' int' ) AS SystemIdle,
2425+ record .value (' (./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]' , ' int' ) AS ProcessUtilization
24072426 FROM (
24082427 SELECT TOP 1 CONVERT (XML , record) AS record
24092428 FROM sys .dm_os_ring_buffers
24102429 WHERE ring_buffer_type = N ' RING_BUFFER_SCHEDULER_MONITOR'
24112430 AND record LIKE ' %<SystemHealth>%'
24122431 ORDER BY timestamp DESC ) AS rb
2413- ) AS y
2414- WHERE 100 - SystemIdle >= 50 ;
2432+ ) AS ShreddedCpuXml
2433+ ) AS OsCpu
2434+ WHERE CpuUsage >= 50 ;
24152435
24162436 /* CPU Utilization - CheckID 23 */
24172437 IF (@Debug = 1 )
@@ -2423,7 +2443,8 @@ If one of them is a lead blocker, consider killing that query.'' AS HowToStopit,
24232443 WITH y
24242444 AS
24252445 (
2426- SELECT CONVERT (VARCHAR (5 ), 100 - ca .c .value (' .' , ' INT' )) AS system_idle,
2446+ /* See earlier comments about SystemIdle on Linux. */
2447+ SELECT CONVERT (VARCHAR (5 ), CASE WHEN @is_windows_operating_system = 1 THEN 100 - ca .c .value (' .' , ' INT' ) ELSE ca2 .p .value (' .' , ' INT' ) END ) AS cpu_usage,
24272448 CONVERT (VARCHAR (30 ), rb .event_date ) AS event_date,
24282449 CONVERT (VARCHAR (8000 ), rb .record ) AS record,
24292450 event_date as event_date_raw
@@ -2436,19 +2457,20 @@ If one of them is a lead blocker, consider killing that query.'' AS HowToStopit,
24362457 WHERE dorb .ring_buffer_type = N ' RING_BUFFER_SCHEDULER_MONITOR'
24372458 AND record LIKE ' %<SystemHealth>%' ) AS rb
24382459 CROSS APPLY rb .record .nodes (' /Record/SchedulerMonitorEvent/SystemHealth/SystemIdle' ) AS ca(c)
2460+ CROSS APPLY rb .record .nodes (' /Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization' ) AS ca2(p)
24392461 )
24402462 INSERT INTO #BlitzFirstResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL , HowToStopIt)
24412463 SELECT TOP 1
24422464 23 ,
24432465 250 ,
24442466 ' Server Info' ,
24452467 ' CPU Utilization' ,
2446- y .system_idle + N ' %. Ring buffer details: ' + CAST (y .record AS NVARCHAR (4000 )),
2447- y .system_idle ,
2468+ y .cpu_usage + N ' %. Ring buffer details: ' + CAST (y .record AS NVARCHAR (4000 )),
2469+ y .cpu_usage ,
24482470 ' https://www.brentozar.com/go/cpu' ,
24492471 STUFF (( SELECT TOP 2147483647
24502472 CHAR (10 ) + CHAR (13 )
2451- + y2 .system_idle
2473+ + y2 .cpu_usage
24522474 + ' % ON '
24532475 + y2 .event_date
24542476 + ' Ring buffer details: '
@@ -2479,7 +2501,12 @@ If one of them is a lead blocker, consider killing that query.'' AS HowToStopit,
24792501 AND record LIKE ' %<SystemHealth>%'
24802502 ORDER BY timestamp DESC ) AS rb
24812503 ) AS y
2482- WHERE 100 - (y .SQLUsage + y .SystemIdle ) >= 25 ;
2504+ WHERE 100 - (y .SQLUsage + y .SystemIdle ) >= 25
2505+ /* SystemIdle is always 0 on Linux, as described earlier.
2506+ We therefore cannot distinguish between a totally idle Linux server and
2507+ a Linux server where SQL Server is being crushed by other CPU-heavy processes.
2508+ We therefore disable this check on Linux. */
2509+ AND @is_windows_operating_system = 1 ;
24832510
24842511 END ; /* IF @Seconds < 30 */
24852512
@@ -3593,18 +3620,24 @@ If one of them is a lead blocker, consider killing that query.'' AS HowToStopit,
35933620 END
35943621
35953622 INSERT INTO #BlitzFirstResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL )
3596- SELECT 24 , 50 , ' Server Performance' , ' High CPU Utilization' , CAST (100 - SystemIdle AS NVARCHAR (20 )) + N ' %. Ring buffer details: ' + CAST (record AS NVARCHAR (4000 )), 100 - SystemIdle, ' https://www.brentozar.com/go/cpu'
3623+ SELECT 24 , 50 , ' Server Performance' , ' High CPU Utilization' , CAST (CpuUsage AS NVARCHAR (20 )) + N ' %. Ring buffer details: ' + CAST (record AS NVARCHAR (4000 )), CpuUsage, ' https://www.brentozar.com/go/cpu'
3624+ FROM (
3625+ SELECT record,
3626+ CASE WHEN @is_windows_operating_system = 1 THEN 100 - SystemIdle ELSE ProcessUtilization END AS CpuUsage
35973627 FROM (
35983628 SELECT record,
3599- record .value (' (./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]' , ' int' ) AS SystemIdle
3629+ record .value (' (./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]' , ' int' ) AS SystemIdle,
3630+ /* See earlier comments about SystemIdle on Linux. */
3631+ record .value (' (./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]' , ' int' ) AS ProcessUtilization
36003632 FROM (
36013633 SELECT TOP 1 CONVERT (XML , record) AS record
36023634 FROM sys .dm_os_ring_buffers
36033635 WHERE ring_buffer_type = N ' RING_BUFFER_SCHEDULER_MONITOR'
36043636 AND record LIKE ' %<SystemHealth>%'
36053637 ORDER BY timestamp DESC ) AS rb
3606- ) AS y
3607- WHERE 100 - SystemIdle >= 50 ;
3638+ ) AS ShreddedCpuXml
3639+ ) AS OsCpu
3640+ WHERE CpuUsage >= 50 ;
36083641
36093642 /* Server Performance - CPU Utilization CheckID 23 */
36103643 IF (@Debug = 1 )
@@ -3613,17 +3646,23 @@ If one of them is a lead blocker, consider killing that query.'' AS HowToStopit,
36133646 END
36143647
36153648 INSERT INTO #BlitzFirstResults (CheckID, Priority, FindingsGroup, Finding, Details, DetailsInt, URL )
3616- SELECT 23 , 250 , ' Server Info' , ' CPU Utilization' , CAST (100 - SystemIdle AS NVARCHAR (20 )) + N ' %. Ring buffer details: ' + CAST (record AS NVARCHAR (4000 )), 100 - SystemIdle, ' https://www.brentozar.com/go/cpu'
3649+ SELECT 23 , 250 , ' Server Info' , ' CPU Utilization' , CAST (CpuUsage AS NVARCHAR (20 )) + N ' %. Ring buffer details: ' + CAST (record AS NVARCHAR (4000 )), CpuUsage, ' https://www.brentozar.com/go/cpu'
3650+ FROM (
3651+ SELECT record,
3652+ CASE WHEN @is_windows_operating_system = 1 THEN 100 - SystemIdle ELSE ProcessUtilization END AS CpuUsage
36173653 FROM (
36183654 SELECT record,
3619- record .value (' (./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]' , ' int' ) AS SystemIdle
3655+ record .value (' (./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]' , ' int' ) AS SystemIdle,
3656+ /* See earlier comments about SystemIdle on Linux. */
3657+ record .value (' (./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]' , ' int' ) AS ProcessUtilization
36203658 FROM (
36213659 SELECT TOP 1 CONVERT (XML , record) AS record
36223660 FROM sys .dm_os_ring_buffers
36233661 WHERE ring_buffer_type = N ' RING_BUFFER_SCHEDULER_MONITOR'
36243662 AND record LIKE ' %<SystemHealth>%'
36253663 ORDER BY timestamp DESC ) AS rb
3626- ) AS y;
3664+ ) AS ShreddedCpuXml
3665+ ) AS OsCpu;
36273666
36283667 END ; /* IF @Seconds >= 30 */
36293668
0 commit comments