solaris-kstat 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +13 -0
- data/README +8 -17
- data/Rakefile +37 -43
- data/ext/solaris/rkstat.c +170 -148
- data/ext/solaris/rkstat.h +276 -288
- data/solaris-kstat.gemspec +24 -29
- data/test/test_solaris_kstat.rb +155 -149
- metadata +20 -10
data/CHANGES
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
== 1.0.2 - 29-Jul-2011
|
2
|
+
* Fixed a bug where the name hash keys could potentially be overwritten if there
|
3
|
+
were multiple statistics for the same name. Thanks go to Jens Deppe for the
|
4
|
+
spot and the patch.
|
5
|
+
* Added the "class" information to the statistics hash.
|
6
|
+
* Rakefile refactored. The old style of library installation has been removed.
|
7
|
+
Use the 'gem' tasks now. In addition, gem creation is now handled via a Rake
|
8
|
+
task now.
|
9
|
+
* Some minor modifications to the gemspec to reflect the changes in the
|
10
|
+
Rakefile, as well as a change required due to the switch from CVS to git.
|
11
|
+
* Added a .gitignore file.
|
12
|
+
* Changed license to Artistic 2.0.
|
13
|
+
|
1
14
|
== 1.0.1 - 27-Aug-2009
|
2
15
|
* Changed the license to Artistic 2.0.
|
3
16
|
* Fixed warnings that could occur if the @module, @name, or @instance
|
data/README
CHANGED
@@ -1,18 +1,11 @@
|
|
1
1
|
== Description
|
2
|
-
Ruby
|
2
|
+
A Ruby interface for the Solaris kstat library.
|
3
3
|
|
4
4
|
== Prerequisites
|
5
|
-
Solaris 8 (2.8) or later.
|
6
|
-
Ruby 1.8.x
|
5
|
+
Solaris 8 (SunOS 2.8) or later.
|
7
6
|
|
8
7
|
== Installation
|
9
|
-
|
10
|
-
rake test (optional)
|
11
|
-
rake install
|
12
|
-
|
13
|
-
=== Gem Installation
|
14
|
-
rake test (optional)
|
15
|
-
rake install_gem
|
8
|
+
gem install solaris-kstat
|
16
9
|
|
17
10
|
== Synopsis
|
18
11
|
require 'solaris/kstat'
|
@@ -20,7 +13,7 @@
|
|
20
13
|
include Solaris
|
21
14
|
|
22
15
|
k = Kstat.new('cpu_info', 0, 'cpu_info0')
|
23
|
-
pp k
|
16
|
+
pp k.record
|
24
17
|
|
25
18
|
{'cpu_info'=>
|
26
19
|
{0=>
|
@@ -64,7 +57,7 @@ Kstat::Error < StandardError
|
|
64
57
|
* sfmmu_percpu_stat
|
65
58
|
|
66
59
|
== Known Bugs
|
67
|
-
You
|
60
|
+
You may receive a couple warnings during the build process. You
|
68
61
|
can ignore these.
|
69
62
|
|
70
63
|
== Designer's Notes
|
@@ -81,13 +74,13 @@ Kstat::Error < StandardError
|
|
81
74
|
Thanks go to Charlie Mills for help with the 'volatile' issue.
|
82
75
|
|
83
76
|
== Future Plans
|
84
|
-
|
77
|
+
Add snaptime and crtime information to the statistics hash.
|
85
78
|
|
86
79
|
== License
|
87
|
-
|
80
|
+
Artistic 2.0
|
88
81
|
|
89
82
|
== Copyright
|
90
|
-
(C) 2003-
|
83
|
+
(C) 2003-2011 Daniel J. Berger
|
91
84
|
All Rights Reserved
|
92
85
|
|
93
86
|
== Warranty
|
@@ -97,8 +90,6 @@ Kstat::Error < StandardError
|
|
97
90
|
|
98
91
|
== Author
|
99
92
|
Daniel J. Berger
|
100
|
-
djberg96 at nospam at gmail dot com
|
101
|
-
imperator on IRC (freenode)
|
102
93
|
|
103
94
|
== See Also
|
104
95
|
kstat(1M)
|
data/Rakefile
CHANGED
@@ -4,56 +4,50 @@ require 'rake/testtask'
|
|
4
4
|
require 'rbconfig'
|
5
5
|
include Config
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
Dir.mkdir('solaris') unless File.exists?('solaris')
|
25
|
-
FileUtils.cp('kstat.so', 'solaris')
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
desc "Install the solaris-kstat package (non-gem)"
|
30
|
-
task :install => [:build] do
|
31
|
-
Dir.chdir('ext') do
|
32
|
-
sh 'make install'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
desc "Install the solaris-kstat package as a gem"
|
37
|
-
task :install_gem do
|
38
|
-
ruby 'solaris-kstat.gemspec'
|
39
|
-
file = Dir["*.gem"].first
|
40
|
-
sh "gem install #{file}"
|
7
|
+
CLEAN.include(
|
8
|
+
'**/*.gem', # Gem files
|
9
|
+
'**/*.rbc', # Rubinius
|
10
|
+
'**/*.o', # C object file
|
11
|
+
'**/*.log', # Ruby extension build log
|
12
|
+
'**/Makefile', # C Makefile
|
13
|
+
'**/conftest.dSYM', # OS X build directory
|
14
|
+
"**/*.#{CONFIG['DLEXT']}" # C shared object
|
15
|
+
)
|
16
|
+
|
17
|
+
desc "Build the solaris-kstat source"
|
18
|
+
task :build do
|
19
|
+
Dir.chdir('ext') do
|
20
|
+
ruby 'extconf.rb'
|
21
|
+
sh 'make'
|
22
|
+
cp 'kstat.so', 'solaris'
|
23
|
+
end
|
41
24
|
end
|
42
25
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
26
|
+
namespace :gem do
|
27
|
+
desc "Create the solaris-kstat gem"
|
28
|
+
task :create => [:clean] do
|
29
|
+
spec = eval(IO.read('solaris-kstat.gemspec'))
|
30
|
+
Gem::Builder.new(spec).build
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Install the solaris-kstat gem"
|
34
|
+
task :install => [:build] do
|
35
|
+
ruby 'solaris-kstat.gemspec'
|
36
|
+
file = Dir["*.gem"].first
|
37
|
+
sh "gem install #{file}"
|
38
|
+
end
|
47
39
|
end
|
48
40
|
|
49
41
|
desc "Run the example program"
|
50
42
|
task :example => [:build] do
|
51
|
-
|
43
|
+
ruby "-Iext examples/example_kstat.rb"
|
52
44
|
end
|
53
45
|
|
54
46
|
Rake::TestTask.new do |t|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
47
|
+
task :test => [:build]
|
48
|
+
t.libs << 'ext'
|
49
|
+
t.verbose = true
|
50
|
+
t.warning = true
|
59
51
|
end
|
52
|
+
|
53
|
+
task :default => :test
|
data/ext/solaris/rkstat.c
CHANGED
@@ -20,8 +20,8 @@ extern "C" {
|
|
20
20
|
VALUE cKstatError;
|
21
21
|
|
22
22
|
static VALUE ks_allocate(VALUE klass){
|
23
|
-
|
24
|
-
|
23
|
+
KstatStruct* ptr;
|
24
|
+
return Data_Make_Struct(klass, KstatStruct, 0, ks_free, ptr);
|
25
25
|
}
|
26
26
|
|
27
27
|
/*
|
@@ -37,36 +37,53 @@ static VALUE ks_allocate(VALUE klass){
|
|
37
37
|
* name defaults to nil (all names).
|
38
38
|
*/
|
39
39
|
VALUE ks_init(int argc, VALUE* argv, VALUE self){
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
KstatStruct* ptr;
|
41
|
+
VALUE v_module, v_instance, v_name;
|
42
|
+
|
43
|
+
Data_Get_Struct(self,KstatStruct,ptr);
|
44
|
+
|
45
|
+
rb_scan_args(argc, argv, "03", &v_module, &v_instance, &v_name);
|
46
|
+
|
47
|
+
if(!NIL_P(v_module)){
|
48
|
+
SafeStringValue(v_module);
|
49
|
+
rb_iv_set(self, "@module", v_module);
|
50
|
+
}
|
51
|
+
else{
|
52
|
+
rb_iv_set(self, "@module", Qnil);
|
53
|
+
}
|
54
|
+
|
55
|
+
if(!NIL_P(v_name)){
|
56
|
+
SafeStringValue(v_name);
|
57
|
+
rb_iv_set(self, "@name", v_name);
|
58
|
+
}
|
59
|
+
else{
|
60
|
+
rb_iv_set(self, "@name", Qnil);
|
61
|
+
}
|
62
|
+
|
63
|
+
if(!NIL_P(v_instance))
|
64
|
+
rb_iv_set(self, "@instance", v_instance);
|
65
|
+
else
|
66
|
+
rb_iv_set(self, "@instance", Qnil);
|
67
|
+
|
68
|
+
return self;
|
69
|
+
}
|
47
70
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
71
|
+
/*
|
72
|
+
* Helper function ks_record which will either return an existing value for
|
73
|
+
* the given key, or assign that key a new empty hash if it has no value
|
74
|
+
* associated with it.
|
75
|
+
*/
|
76
|
+
VALUE get_hash_for_key(VALUE v_hash, VALUE v_key){
|
77
|
+
volatile VALUE v_new_hash;
|
55
78
|
|
56
|
-
|
57
|
-
SafeStringValue(v_name);
|
58
|
-
rb_iv_set(self, "@name", v_name);
|
59
|
-
}
|
60
|
-
else{
|
61
|
-
rb_iv_set(self, "@name", Qnil);
|
62
|
-
}
|
79
|
+
v_new_hash = rb_hash_aref(v_hash, v_key);
|
63
80
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
81
|
+
if(NIL_P(v_new_hash)){
|
82
|
+
v_new_hash = rb_hash_new();
|
83
|
+
rb_hash_aset(v_hash, v_key, v_new_hash);
|
84
|
+
}
|
68
85
|
|
69
|
-
|
86
|
+
return v_new_hash;
|
70
87
|
}
|
71
88
|
|
72
89
|
/*
|
@@ -75,141 +92,146 @@ VALUE ks_init(int argc, VALUE* argv, VALUE self){
|
|
75
92
|
* The more specific your criterion, the less data you will receive.
|
76
93
|
*/
|
77
94
|
VALUE ks_record(VALUE self){
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
ptr->ksp = ptr->ksp->ks_next;
|
134
|
-
continue;
|
135
|
-
}
|
136
|
-
|
137
|
-
/* If an instance is specified, ignore instances that don't match */
|
138
|
-
if( (instance != -1) && (instance != ptr->ksp->ks_instance) ){
|
139
|
-
ptr->ksp = ptr->ksp->ks_next;
|
140
|
-
continue;
|
141
|
-
}
|
142
|
-
|
143
|
-
/* If a name is specified, ignore names that don't match */
|
144
|
-
if( (name) && (strcmp(name,ptr->ksp->ks_name)) ){
|
145
|
-
ptr->ksp = ptr->ksp->ks_next;
|
146
|
-
continue;
|
147
|
-
}
|
148
|
-
|
149
|
-
/* Call the appropriate data mapper based on ks_type */
|
150
|
-
switch(ptr->ksp->ks_type){
|
151
|
-
case KSTAT_TYPE_NAMED:
|
152
|
-
kstat_read(ptr->kc, ptr->ksp, NULL);
|
153
|
-
v_s_hash = map_named_data_type(ptr->ksp);
|
154
|
-
break;
|
155
|
-
case KSTAT_TYPE_IO:
|
156
|
-
kstat_read(ptr->kc, ptr->ksp, &kio);
|
157
|
-
v_s_hash = map_io_data_type(&kio);
|
158
|
-
break;
|
159
|
-
case KSTAT_TYPE_TIMER:
|
160
|
-
kstat_read(ptr->kc, ptr->ksp, &kt);
|
161
|
-
v_s_hash = map_timer_data_type(&kt);
|
162
|
-
case KSTAT_TYPE_INTR:
|
163
|
-
kstat_read(ptr->kc, ptr->ksp, NULL);
|
164
|
-
v_s_hash = map_intr_data_type(ptr->ksp);
|
165
|
-
break;
|
166
|
-
case KSTAT_TYPE_RAW:
|
167
|
-
kstat_read(ptr->kc, ptr->ksp, NULL);
|
168
|
-
v_s_hash = map_raw_data_type(ptr->ksp);
|
169
|
-
break;
|
170
|
-
default:
|
171
|
-
rb_raise(cKstatError,"Unknown data record type");
|
172
|
-
}
|
173
|
-
|
174
|
-
rb_hash_aset(v_n_hash, rb_str_new2(ptr->ksp->ks_name), v_s_hash);
|
175
|
-
rb_hash_aset(v_i_hash, INT2FIX(ptr->ksp->ks_instance), v_n_hash);
|
176
|
-
rb_hash_aset(v_m_hash, rb_str_new2(ptr->ksp->ks_module), v_i_hash);
|
95
|
+
volatile VALUE v_m_hash, v_i_hash, v_n_hash, v_s_hash;
|
96
|
+
KstatStruct* ptr;
|
97
|
+
kstat_io_t kio;
|
98
|
+
kstat_timer_t kt;
|
99
|
+
char* module;
|
100
|
+
char* name;
|
101
|
+
int instance = -1; // -1 represents all instances (the default)
|
102
|
+
|
103
|
+
VALUE v_module, v_instance, v_name;
|
104
|
+
|
105
|
+
Data_Get_Struct(self,KstatStruct,ptr);
|
106
|
+
|
107
|
+
v_m_hash = rb_hash_new(); // Module name is key, holds v_i_hashes
|
108
|
+
|
109
|
+
v_module = rb_iv_get(self, "@module");
|
110
|
+
v_instance = rb_iv_get(self, "@instance");
|
111
|
+
v_name = rb_iv_get(self, "@name");
|
112
|
+
|
113
|
+
// Module is NULL by default (i.e. all modules are returned)
|
114
|
+
if(NIL_P(v_module))
|
115
|
+
module = NULL;
|
116
|
+
else
|
117
|
+
module = StringValuePtr(v_module);
|
118
|
+
|
119
|
+
// Instance defaults to -1 (i.e. all instances are returned)
|
120
|
+
if(!NIL_P(v_instance))
|
121
|
+
instance = NUM2INT(v_instance);
|
122
|
+
|
123
|
+
// Name is NULL by default (i.e. all names are returned)
|
124
|
+
if(NIL_P(v_name))
|
125
|
+
name = NULL;
|
126
|
+
else
|
127
|
+
name = StringValuePtr(v_name);
|
128
|
+
|
129
|
+
// A failure probably means the module, instance or name doesn't exist
|
130
|
+
if((ptr->kc = kstat_open()) == NULL)
|
131
|
+
rb_raise(cKstatError, "kstat_open() failure: %s", strerror(errno));
|
132
|
+
|
133
|
+
/*
|
134
|
+
* Traverse the kstat chain, looking for matches based on supplied data.
|
135
|
+
* A failure likely means a non-existant module or name was provided.
|
136
|
+
*/
|
137
|
+
if((ptr->ksp = kstat_lookup(ptr->kc, module, instance, name)) == NULL)
|
138
|
+
rb_raise(cKstatError, "kstat_lookup() failure: %s", strerror(errno));
|
139
|
+
|
140
|
+
// Sync the chain with the kernel
|
141
|
+
if(kstat_chain_update(ptr->kc) == -1)
|
142
|
+
rb_raise(cKstatError, "kstat_chain_update() failure: %s", strerror(errno));
|
143
|
+
|
144
|
+
while(ptr->ksp){
|
145
|
+
// If a module is specified, ignore modules that don't match
|
146
|
+
if((module) && (strcmp(module,ptr->ksp->ks_module))){
|
147
|
+
ptr->ksp = ptr->ksp->ks_next;
|
148
|
+
continue;
|
149
|
+
}
|
177
150
|
|
151
|
+
// If an instance is specified, ignore instances that don't match
|
152
|
+
if((instance != -1) && (instance != ptr->ksp->ks_instance)){
|
178
153
|
ptr->ksp = ptr->ksp->ks_next;
|
179
|
-
|
154
|
+
continue;
|
155
|
+
}
|
180
156
|
|
181
|
-
|
157
|
+
// If a name is specified, ignore names that don't match
|
158
|
+
if((name) && (strcmp(name,ptr->ksp->ks_name))){
|
159
|
+
ptr->ksp = ptr->ksp->ks_next;
|
160
|
+
continue;
|
161
|
+
}
|
162
|
+
|
163
|
+
// Call the appropriate data mapper based on ks_type
|
164
|
+
switch(ptr->ksp->ks_type){
|
165
|
+
case KSTAT_TYPE_NAMED:
|
166
|
+
kstat_read(ptr->kc, ptr->ksp, NULL);
|
167
|
+
v_s_hash = map_named_data_type(ptr->ksp);
|
168
|
+
break;
|
169
|
+
case KSTAT_TYPE_IO:
|
170
|
+
kstat_read(ptr->kc, ptr->ksp, &kio);
|
171
|
+
v_s_hash = map_io_data_type(&kio);
|
172
|
+
break;
|
173
|
+
case KSTAT_TYPE_TIMER:
|
174
|
+
kstat_read(ptr->kc, ptr->ksp, &kt);
|
175
|
+
v_s_hash = map_timer_data_type(&kt);
|
176
|
+
case KSTAT_TYPE_INTR:
|
177
|
+
kstat_read(ptr->kc, ptr->ksp, NULL);
|
178
|
+
v_s_hash = map_intr_data_type(ptr->ksp);
|
179
|
+
break;
|
180
|
+
case KSTAT_TYPE_RAW:
|
181
|
+
kstat_read(ptr->kc, ptr->ksp, NULL);
|
182
|
+
v_s_hash = map_raw_data_type(ptr->ksp);
|
183
|
+
break;
|
184
|
+
default:
|
185
|
+
rb_raise(cKstatError,"Unknown data record type");
|
186
|
+
}
|
187
|
+
|
188
|
+
/* Set the class for this set of statistics */
|
189
|
+
if(ptr->ksp->ks_class)
|
190
|
+
rb_hash_aset(v_s_hash, rb_str_new2("class"), rb_str_new2(ptr->ksp->ks_class));
|
191
|
+
|
192
|
+
v_i_hash = get_hash_for_key(v_m_hash, rb_str_new2(ptr->ksp->ks_module));
|
193
|
+
v_n_hash = get_hash_for_key(v_i_hash, INT2FIX(ptr->ksp->ks_instance));
|
194
|
+
|
195
|
+
rb_hash_aset(v_n_hash, rb_str_new2(ptr->ksp->ks_name), v_s_hash);
|
196
|
+
rb_hash_aset(v_i_hash, INT2FIX(ptr->ksp->ks_instance), v_n_hash);
|
197
|
+
rb_hash_aset(v_m_hash, rb_str_new2(ptr->ksp->ks_module), v_i_hash);
|
198
|
+
|
199
|
+
ptr->ksp = ptr->ksp->ks_next;
|
200
|
+
}
|
201
|
+
|
202
|
+
return v_m_hash;
|
182
203
|
}
|
183
204
|
|
184
205
|
void Init_kstat(){
|
185
|
-
|
206
|
+
VALUE mSolaris, cKstat;
|
207
|
+
|
208
|
+
/* The Solaris module only serves as a toplevel namespace */
|
209
|
+
mSolaris = rb_define_module("Solaris");
|
186
210
|
|
187
|
-
|
188
|
-
|
211
|
+
/* The Kstat class encapsulates kstat (kernel statistics) information */
|
212
|
+
cKstat = rb_define_class_under(mSolaris, "Kstat", rb_cObject);
|
189
213
|
|
190
|
-
|
191
|
-
|
214
|
+
/* The Kstat::Error class is raised if any of the Kstat methods fail */
|
215
|
+
cKstatError = rb_define_class_under(cKstat, "Error", rb_eStandardError);
|
192
216
|
|
193
|
-
|
194
|
-
cKstatError = rb_define_class_under(cKstat, "Error", rb_eStandardError);
|
217
|
+
rb_define_alloc_func(cKstat, ks_allocate);
|
195
218
|
|
196
|
-
|
219
|
+
// Instance Methods
|
197
220
|
|
198
|
-
|
199
|
-
|
200
|
-
rb_define_method(cKstat, "record", ks_record, 0);
|
221
|
+
rb_define_method(cKstat, "initialize", ks_init, -1);
|
222
|
+
rb_define_method(cKstat, "record", ks_record, 0);
|
201
223
|
|
202
|
-
|
203
|
-
|
224
|
+
// Kernel module
|
225
|
+
rb_define_attr(cKstat, "module", 1, 1);
|
204
226
|
|
205
|
-
|
206
|
-
|
227
|
+
// Index of module entity
|
228
|
+
rb_define_attr(cKstat, "instance", 1, 1);
|
207
229
|
|
208
|
-
|
209
|
-
|
230
|
+
// Unique name within module
|
231
|
+
rb_define_attr(cKstat, "name", 1, 1);
|
210
232
|
|
211
|
-
|
212
|
-
|
233
|
+
/* 1.0.2: The version of the solaris-kstat library */
|
234
|
+
rb_define_const(cKstat, "VERSION", rb_str_new2(SOLARIS_KSTAT_VERSION));
|
213
235
|
}
|
214
236
|
|
215
237
|
#ifdef __cplusplus
|