solaris-kstat 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|