cpuinfo 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,796 @@
1
+ require 'win32ole'
2
+ require 'socket'
3
+
4
+ # See Ruby bugs #2618 and #7681. This is a workaround.
5
+ BEGIN{
6
+ require 'win32ole'
7
+ if RUBY_VERSION.to_f < 2.0
8
+ WIN32OLE.ole_initialize
9
+ at_exit { WIN32OLE.ole_uninitialize }
10
+ end
11
+ }
12
+
13
+ # The Sys module serves only as a namespace
14
+ module Sys
15
+ # Encapsulates system CPU information
16
+ class CPU
17
+ # Error raised if any of the Sys::CPU methods fail.
18
+ class Error < StandardError; end
19
+
20
+ private
21
+
22
+ # Base connect string
23
+ BASE_CS = "winmgmts:{impersonationLevel=impersonate}" # :nodoc:
24
+
25
+ # Fields used in the CPUStruct
26
+ fields = %w[
27
+ address_width
28
+ architecture
29
+ availability
30
+ caption
31
+ config_manager_error_code
32
+ config_manager_user_config
33
+ cpu_status
34
+ creation_class_name
35
+ freq
36
+ voltage
37
+ data_width
38
+ description
39
+ device_id
40
+ error_cleared?
41
+ error_description
42
+ ext_clock
43
+ family
44
+ install_date
45
+ l2_cache_size
46
+ l2_cache_speed
47
+ last_error_code
48
+ level
49
+ load_avg
50
+ manufacturer
51
+ max_clock_speed
52
+ name
53
+ other_family_description
54
+ pnp_device_id
55
+ power_management_supported?
56
+ power_management_capabilities
57
+ processor_id
58
+ processor_type
59
+ revision
60
+ role
61
+ socket_designation
62
+ status
63
+ status_info
64
+ stepping
65
+ system_creation_class_name
66
+ system_name
67
+ unique_id
68
+ upgrade_method
69
+ version
70
+ voltage_caps
71
+ ]
72
+
73
+ # The struct returned by the CPU.processors method
74
+ CPUStruct = Struct.new("CPUStruct", *fields) # :nodoc:
75
+
76
+ public
77
+
78
+ # Returns the +host+ CPU's architecture, or nil if it cannot be
79
+ # determined.
80
+ #
81
+ def self.architecture(host=Socket.gethostname)
82
+ cs = BASE_CS + "//#{host}/root/cimv2:Win32_Processor='cpu0'"
83
+ begin
84
+ wmi = WIN32OLE.connect(cs)
85
+ rescue WIN32OLERuntimeError => e
86
+ raise Error, e
87
+ else
88
+ self.get_cpu_arch(wmi.Architecture)
89
+ end
90
+ end
91
+
92
+ # Returns an integer indicating the speed (i.e. frequency in Mhz) of
93
+ # +cpu_num+ on +host+, or the localhost if no +host+ is specified.
94
+ # If +cpu_num+ +1 is greater than the number of cpu's on your system
95
+ # or this call fails for any other reason, a Error is raised.
96
+ #
97
+ def self.freq(cpu_num = 0, host = Socket.gethostname)
98
+ cs = BASE_CS + "//#{host}/root/cimv2:Win32_Processor='cpu#{cpu_num}'"
99
+ begin
100
+ wmi = WIN32OLE.connect(cs)
101
+ rescue WIN32OLERuntimeError => e
102
+ raise Error, e
103
+ else
104
+ return wmi.CurrentClockSpeed
105
+ end
106
+ end
107
+
108
+ # Returns the load capacity for +cpu_num+ on +host+, or the localhost
109
+ # if no host is specified, averaged to the last second. Processor
110
+ # loading refers to the total computing burden for each processor at
111
+ # one time.
112
+ #
113
+ # Note that this attribute is actually the LoadPercentage. I may use
114
+ # one of the Win32_Perf* classes in the future.
115
+ #
116
+ def self.load_avg(cpu_num = 0, host = Socket.gethostname)
117
+ cs = BASE_CS + "//#{host}/root/cimv2:Win32_Processor='cpu#{cpu_num}'"
118
+ begin
119
+ wmi = WIN32OLE.connect(cs)
120
+ rescue WIN32OLERuntimeError => e
121
+ raise Error, e
122
+ else
123
+ return wmi.LoadPercentage
124
+ end
125
+ end
126
+
127
+ # Returns a string indicating the cpu model, e.g. Intel Pentium 4.
128
+ #
129
+ def self.model(host = Socket.gethostname)
130
+ cs = BASE_CS + "//#{host}/root/cimv2:Win32_Processor='cpu0'"
131
+ begin
132
+ wmi = WIN32OLE.connect(cs)
133
+ rescue WIN32OLERuntimeError => e
134
+ raise Error, e
135
+ else
136
+ return wmi.Name
137
+ end
138
+ end
139
+
140
+ # Returns an integer indicating the number of cpu's on the system.
141
+ #--
142
+ # This (oddly) requires a different class.
143
+ #
144
+ def self.num_cpu(host = Socket.gethostname)
145
+ cs = BASE_CS + "//#{host}/root/cimv2:Win32_ComputerSystem='#{host}'"
146
+ begin
147
+ wmi = WIN32OLE.connect(cs)
148
+ rescue WIN32OLERuntimeError => e
149
+ raise Error, e
150
+ else
151
+ return wmi.NumberOfProcessors
152
+ end
153
+ end
154
+
155
+ # Returns a CPUStruct for each CPU on +host+, or the localhost if no
156
+ # +host+ is specified. A CPUStruct contains the following members:
157
+ #
158
+ # * address_width
159
+ # * architecture
160
+ # * availability
161
+ # * caption
162
+ # * config_manager_error_code
163
+ # * config_manager_user_config
164
+ # * cpu_status
165
+ # * creation_class_name
166
+ # * freq
167
+ # * voltage
168
+ # * data_width
169
+ # * description
170
+ # * device_id
171
+ # * error_cleared?
172
+ # * error_description
173
+ # * ext_clock
174
+ # * family
175
+ # * install_date
176
+ # * l2_cache_size
177
+ # * l2_cache_speed
178
+ # * last_error_code
179
+ # * level
180
+ # * load_avg
181
+ # * manufacturer
182
+ # * max_clock_speed
183
+ # * name
184
+ # * other_family_description
185
+ # * pnp_device_id
186
+ # * power_management_supported?
187
+ # * power_management_capabilities
188
+ # * processor_id
189
+ # * processor_type
190
+ # * revision
191
+ # * role
192
+ # * socket_designation
193
+ # * status
194
+ # * status_info
195
+ # * stepping
196
+ # * system_creation_class_name
197
+ # * system_name
198
+ # * unique_id
199
+ # * upgrade_method
200
+ # * version
201
+ # * voltage_caps
202
+ #
203
+ # Note that not all of these members will necessarily be defined.
204
+ #
205
+ def self.processors(host = Socket.gethostname) # :yields: CPUStruct
206
+ begin
207
+ wmi = WIN32OLE.connect(BASE_CS + "//#{host}/root/cimv2")
208
+ rescue WIN32OLERuntimeError => e
209
+ raise Error, e
210
+ else
211
+ wmi.InstancesOf("Win32_Processor").each{ |cpu|
212
+ yield CPUStruct.new(
213
+ cpu.AddressWidth,
214
+ self.get_cpu_arch(cpu.Architecture),
215
+ self.get_availability(cpu.Availability),
216
+ cpu.Caption,
217
+ self.get_cmec(cpu.ConfigManagerErrorCode),
218
+ cpu.ConfigManagerUserConfig,
219
+ get_status(cpu.CpuStatus),
220
+ cpu.CreationClassName,
221
+ cpu.CurrentClockSpeed,
222
+ cpu.CurrentVoltage,
223
+ cpu.DataWidth,
224
+ cpu.Description,
225
+ cpu.DeviceId,
226
+ cpu.ErrorCleared,
227
+ cpu.ErrorDescription,
228
+ cpu.ExtClock,
229
+ self.get_family(cpu.Family),
230
+ cpu.InstallDate,
231
+ cpu.L2CacheSize,
232
+ cpu.L2CacheSpeed,
233
+ cpu.LastErrorCode,
234
+ cpu.Level,
235
+ cpu.LoadPercentage,
236
+ cpu.Manufacturer,
237
+ cpu.MaxClockSpeed,
238
+ cpu.Name,
239
+ cpu.OtherFamilyDescription,
240
+ cpu.PNPDeviceID,
241
+ cpu.PowerManagementSupported,
242
+ cpu.PowerManagementCapabilities,
243
+ cpu.ProcessorId,
244
+ self.get_processor_type(cpu.ProcessorType),
245
+ cpu.Revision,
246
+ cpu.Role,
247
+ cpu.SocketDesignation,
248
+ cpu.Status,
249
+ cpu.StatusInfo,
250
+ cpu.Stepping,
251
+ cpu.SystemCreationClassName,
252
+ cpu.SystemName,
253
+ cpu.UniqueId,
254
+ self.get_upgrade_method(cpu.UpgradeMethod),
255
+ cpu.Version,
256
+ self.get_voltage_caps(cpu.VoltageCaps)
257
+ )
258
+ }
259
+ end
260
+ end
261
+
262
+ # Returns a string indicating the type of processor, e.g. GenuineIntel.
263
+ #
264
+ def self.cpu_type(host = Socket.gethostname)
265
+ cs = BASE_CS + "//#{host}/root/cimv2:Win32_Processor='cpu0'"
266
+ begin
267
+ wmi = WIN32OLE.connect(cs)
268
+ rescue WIN32OLERuntimeError => e
269
+ raise Error, e
270
+ else
271
+ return wmi.Manufacturer
272
+ end
273
+ end
274
+
275
+ private
276
+
277
+ # Convert the ConfigManagerErrorCode number to its corresponding string
278
+ # Note that this value returns nil on my system.
279
+ #
280
+ def self.get_cmec(num)
281
+ case
282
+ when 0
283
+ str = "The device is working properly."
284
+ return str
285
+ when 1
286
+ str = "The device is not configured correctly."
287
+ return str
288
+ when 2
289
+ str = "Windows cannot load the driver for the device."
290
+ return str
291
+ when 3
292
+ str = "The driver for the device might be corrupted, or the"
293
+ str << " system may be running low on memory or other"
294
+ str << " resources."
295
+ return str
296
+ when 4
297
+ str = "The device is not working properly. One of the drivers"
298
+ str << " or the registry might be corrupted."
299
+ return str
300
+ when 5
301
+ str = "The driver for this device needs a resource that"
302
+ str << " Windows cannot manage."
303
+ return str
304
+ when 6
305
+ str = "The boot configuration for this device conflicts with"
306
+ str << " other devices."
307
+ return str
308
+ when 7
309
+ str = "Cannot filter."
310
+ return str
311
+ when 8
312
+ str = "The driver loader for the device is missing."
313
+ return str
314
+ when 9
315
+ str = "This device is not working properly because the"
316
+ str << " controlling firmware is reporting the resources"
317
+ str << " for the device incorrectly."
318
+ return str
319
+ when 10
320
+ str = "This device cannot start."
321
+ return str
322
+ when 11
323
+ str = "This device failed."
324
+ return str
325
+ when 12
326
+ str = "This device cannot find enough free resources that"
327
+ str << " it can use."
328
+ return str
329
+ when 13
330
+ str = "Windows cannot verify this device's resources."
331
+ return str
332
+ when 14
333
+ str = "This device cannot work properly until you restart"
334
+ str << " your computer."
335
+ return str
336
+ when 15
337
+ str = "This device is not working properly because there is"
338
+ str << " probably a re-enumeration problem."
339
+ return str
340
+ when 16
341
+ str = "Windows cannot identify all the resources this device "
342
+ str << " uses."
343
+ return str
344
+ when 17
345
+ str = "This device is asking for an unknown resource type."
346
+ return str
347
+ when 18
348
+ str = "Reinstall the drivers for this device."
349
+ return str
350
+ when 19
351
+ str = "Failure using the VXD loader."
352
+ return str
353
+ when 20
354
+ str = "Your registry might be corrupted."
355
+ return str
356
+ when 21
357
+ str = "System failure: try changing the driver for this device."
358
+ str << " If that does not work, see your hardware documentation."
359
+ str << " Windows is removing this device."
360
+ return str
361
+ when 22
362
+ str = "This device is disabled."
363
+ return str
364
+ when 23
365
+ str = "System failure: try changing the driver for this device."
366
+ str << "If that doesn't work, see your hardware documentation."
367
+ return str
368
+ when 24
369
+ str = "This device is not present, not working properly, or"
370
+ str << " does not have all its drivers installed."
371
+ return str
372
+ when 25
373
+ str = "Windows is still setting up this device."
374
+ return str
375
+ when 26
376
+ str = "Windows is still setting up this device."
377
+ return str
378
+ when 27
379
+ str = "This device does not have valid log configuration."
380
+ return str
381
+ when 28
382
+ str = "The drivers for this device are not installed."
383
+ return str
384
+ when 29
385
+ str = "This device is disabled because the firmware of the"
386
+ str << " device did not give it the required resources."
387
+ return str
388
+ when 30
389
+ str = "This device is using an Interrupt Request (IRQ)"
390
+ str << " resource that another device is using."
391
+ return str
392
+ when 31
393
+ str = "This device is not working properly because Windows"
394
+ str << " cannot load the drivers required for this device"
395
+ return str
396
+ else
397
+ return nil
398
+ end
399
+ end
400
+
401
+ # Convert an cpu architecture number to a string
402
+ def self.get_cpu_arch(num)
403
+ case num
404
+ when 0
405
+ return "x86"
406
+ when 1
407
+ return "MIPS"
408
+ when 2
409
+ return "Alpha"
410
+ when 3
411
+ return "PowerPC"
412
+ when 6
413
+ return "IA64"
414
+ when 9
415
+ return "x64"
416
+ else
417
+ return nil
418
+ end
419
+ end
420
+
421
+ # convert an Availability number into a string
422
+ def self.get_availability(num)
423
+ case num
424
+ when 1
425
+ return "Other"
426
+ when 2
427
+ return "Unknown"
428
+ when 3
429
+ return "Running"
430
+ when 4
431
+ return "Warning"
432
+ when 5
433
+ return "In Test"
434
+ when 6
435
+ return "Not Applicable"
436
+ when 7
437
+ return "Power Off"
438
+ when 8
439
+ return "Off Line"
440
+ when 9
441
+ return "Off Duty"
442
+ when 10
443
+ return "Degraded"
444
+ when 11
445
+ return "Not Installed"
446
+ when 12
447
+ return "Install Error"
448
+ when 13
449
+ return "Power Save - Unknown"
450
+ when 14
451
+ return "Power Save - Low Power Mode"
452
+ when 15
453
+ return "Power Save - Standby"
454
+ when 16
455
+ return "Power Cycle"
456
+ when 17
457
+ return "Power Save - Warning"
458
+ when 18
459
+ return "Paused"
460
+ when 19
461
+ return "Not Ready"
462
+ when 20
463
+ return "Not Configured"
464
+ when 21
465
+ return "Quiesced"
466
+ else
467
+ return nil
468
+ end
469
+ end
470
+
471
+ # convert CpuStatus to a string form. Note that values 5 and 6 are
472
+ # skipped because they're reserved.
473
+ def self.get_status(num)
474
+ case num
475
+ when 0
476
+ return "Unknown"
477
+ when 1
478
+ return "Enabled"
479
+ when 2
480
+ return "Disabled by User via BIOS Setup"
481
+ when 3
482
+ return "Disabled By BIOS (POST Error)"
483
+ when 4
484
+ return "Idle"
485
+ when 7
486
+ return "Other"
487
+ else
488
+ return nil
489
+ end
490
+ end
491
+
492
+ # Convert a family number into the equivalent string
493
+ def self.get_family(num)
494
+ case num
495
+ when 1
496
+ return "Other"
497
+ when 2
498
+ return "Unknown"
499
+ when 3
500
+ return "8086"
501
+ when 4
502
+ return "80286"
503
+ when 5
504
+ return "80386"
505
+ when 6
506
+ return "80486"
507
+ when 7
508
+ return "8087"
509
+ when 8
510
+ return "80287"
511
+ when 9
512
+ return "80387"
513
+ when 10
514
+ return "80487"
515
+ when 11
516
+ return "Pentium?"
517
+ when 12
518
+ return "Pentium?"
519
+ when 13
520
+ return "Pentium?"
521
+ when 14
522
+ return "Pentium?"
523
+ when 15
524
+ return "Celeron?"
525
+ when 16
526
+ return "Pentium?"
527
+ when 17
528
+ return "Pentium?"
529
+ when 18
530
+ return "M1"
531
+ when 19
532
+ return "M2"
533
+ when 24
534
+ return "K5"
535
+ when 25
536
+ return "K6"
537
+ when 26
538
+ return "K6-2"
539
+ when 27
540
+ return "K6-3"
541
+ when 28
542
+ return "AMD"
543
+ when 29
544
+ return "AMD?"
545
+ when 30
546
+ return "AMD2900"
547
+ when 31
548
+ return "K6-2+"
549
+ when 32
550
+ return "Power"
551
+ when 33
552
+ return "Power"
553
+ when 34
554
+ return "Power"
555
+ when 35
556
+ return "Power"
557
+ when 36
558
+ return "Power"
559
+ when 37
560
+ return "Power"
561
+ when 38
562
+ return "Power"
563
+ when 39
564
+ return "Power"
565
+ when 48
566
+ return "Alpha"
567
+ when 49
568
+ return "Alpha"
569
+ when 50
570
+ return "Alpha"
571
+ when 51
572
+ return "Alpha"
573
+ when 52
574
+ return "Alpha"
575
+ when 53
576
+ return "Alpha"
577
+ when 54
578
+ return "Alpha"
579
+ when 55
580
+ return "Alpha"
581
+ when 64
582
+ return "MIPS"
583
+ when 65
584
+ return "MIPS"
585
+ when 66
586
+ return "MIPS"
587
+ when 67
588
+ return "MIPS"
589
+ when 68
590
+ return "MIPS"
591
+ when 69
592
+ return "MIPS"
593
+ when 80
594
+ return "SPARC"
595
+ when 81
596
+ return "SuperSPARC"
597
+ when 82
598
+ return "microSPARC"
599
+ when 83
600
+ return "microSPARC"
601
+ when 84
602
+ return "UltraSPARC"
603
+ when 85
604
+ return "UltraSPARC"
605
+ when 86
606
+ return "UltraSPARC"
607
+ when 87
608
+ return "UltraSPARC"
609
+ when 88
610
+ return "UltraSPARC"
611
+ when 96
612
+ return "68040"
613
+ when 97
614
+ return "68xxx"
615
+ when 98
616
+ return "68000"
617
+ when 99
618
+ return "68010"
619
+ when 100
620
+ return "68020"
621
+ when 101
622
+ return "68030"
623
+ when 112
624
+ return "Hobbit"
625
+ when 120
626
+ return "Crusoe?"
627
+ when 121
628
+ return "Crusoe?"
629
+ when 128
630
+ return "Weitek"
631
+ when 130
632
+ return "Itanium?"
633
+ when 144
634
+ return "PA-RISC"
635
+ when 145
636
+ return "PA-RISC"
637
+ when 146
638
+ return "PA-RISC"
639
+ when 147
640
+ return "PA-RISC"
641
+ when 148
642
+ return "PA-RISC"
643
+ when 149
644
+ return "PA-RISC"
645
+ when 150
646
+ return "PA-RISC"
647
+ when 160
648
+ return "V30"
649
+ when 176
650
+ return "Pentium?"
651
+ when 177
652
+ return "Pentium?"
653
+ when 178
654
+ return "Pentium?"
655
+ when 179
656
+ return "Intel?"
657
+ when 180
658
+ return "AS400"
659
+ when 181
660
+ return "Intel?"
661
+ when 182
662
+ return "AMD"
663
+ when 183
664
+ return "AMD"
665
+ when 184
666
+ return "Intel?"
667
+ when 185
668
+ return "AMD"
669
+ when 190
670
+ return "K7"
671
+ when 200
672
+ return "IBM390"
673
+ when 201
674
+ return "G4"
675
+ when 202
676
+ return "G5"
677
+ when 250
678
+ return "i860"
679
+ when 251
680
+ return "i960"
681
+ when 260
682
+ return "SH-3"
683
+ when 261
684
+ return "SH-4"
685
+ when 280
686
+ return "ARM"
687
+ when 281
688
+ return "StrongARM"
689
+ when 300
690
+ return "6x86"
691
+ when 301
692
+ return "MediaGX"
693
+ when 302
694
+ return "MII"
695
+ when 320
696
+ return "WinChip"
697
+ when 350
698
+ return "DSP"
699
+ when 500
700
+ return "Video"
701
+ else
702
+ return nil
703
+ end
704
+ end
705
+
706
+ # Convert power management capabilities number to its equivalent string
707
+ def self.get_pmc(num)
708
+ case num
709
+ when 0
710
+ return "Unknown"
711
+ when 1
712
+ return "Not Supported"
713
+ when 2
714
+ return "Disabled"
715
+ when 3
716
+ return "Enabled"
717
+ when 4
718
+ return "Power Saving Modes Entered Automatically"
719
+ when 5
720
+ return "Power State Settable"
721
+ when 6
722
+ return "Power Cycling Supported"
723
+ when 7
724
+ return "Timed Power On Supported"
725
+ else
726
+ return nil
727
+ end
728
+ end
729
+
730
+ # Convert a processor type into its equivalent string
731
+ def self.get_processor_type(num)
732
+ case num
733
+ when 1
734
+ return "Other"
735
+ when 2
736
+ return "Unknown"
737
+ when 3
738
+ return "Central Processor"
739
+ when 4
740
+ return "Math Processor"
741
+ when 5
742
+ return "DSP Processor"
743
+ when 6
744
+ return "Video Processor"
745
+ else
746
+ return nil
747
+ end
748
+ end
749
+
750
+ # Convert an upgrade method into its equivalent string
751
+ def self.get_upgrade_method(num)
752
+ case num
753
+ when 1
754
+ return "Other"
755
+ when 2
756
+ return "Unknown"
757
+ when 3
758
+ return "Daughter Board"
759
+ when 4
760
+ return "ZIF Socket"
761
+ when 5
762
+ return "Replacement/Piggy Back"
763
+ when 6
764
+ return "None"
765
+ when 7
766
+ return "LIF Socket"
767
+ when 8
768
+ return "Slot 1"
769
+ when 9
770
+ return "Slot 2"
771
+ when 10
772
+ return "370 Pin Socket"
773
+ when 11
774
+ return "Slot A"
775
+ when 12
776
+ return "Slot M"
777
+ else
778
+ return nil
779
+ end
780
+ end
781
+
782
+ # Convert return values to voltage cap values (floats)
783
+ def self.get_voltage_caps(num)
784
+ case num
785
+ when 1
786
+ return 5.0
787
+ when 2
788
+ return 3.3
789
+ when 4
790
+ return 2.9
791
+ else
792
+ return nil
793
+ end
794
+ end
795
+ end
796
+ end