-
Notifications
You must be signed in to change notification settings - Fork 174
WIP: Split SWbemServices initialization out of Query method #23
Conversation
I don't know if this is relevant but have you considered |
Thanks for the link! In this case I don't think we need to worry about thread safety or sync/locks as the creation of the default instance can be managed in the init function. |
Finished with the first draft of SWbemServices worker. I left in a bunch of print statements to show the code execution path. @captncraig Ready for a code review tomorrow AM (I'll be out tomorrow afternoon) or on Monday.
|
swbemservices.go
Outdated
return err //Send error to caller | ||
} | ||
break WaitForFinishedSignal | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove default case. This makes a busy loop and burns cpu while waiting.
swbemservices.go
Outdated
type queryRequest struct { | ||
query string | ||
dst interface{} | ||
args interface{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be []interface{}
swbemservices.go
Outdated
return nil, err //Send error to caller | ||
} | ||
break WaitForProcessSignal | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No default case here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you also don't need the for/selects in these loops. Most of them look like a single channel read.
swbemservices.go
Outdated
close(s.closeError) | ||
} | ||
} | ||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No default anywhere.
swbemservices.go
Outdated
fmt.Println("Close: sending close request") | ||
var result error | ||
ce := make(chan error) | ||
s.closeError = ce //Race condition if multiple callers to close. May need to lock here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. a lock for close would be good. Make sure to check queries after you get the lock as well. It could be closed / nil.
swbemservices.go
Outdated
} | ||
|
||
// This method will be called on the background thread and must clean up all WMI/OLE and chan resources | ||
func (s *SWbemServices) closeBackground() error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you defer in the process function, closeBackground is unnecessary.
swbemservices.go
Outdated
fmt.Println("process: initialized. closing initError") | ||
close(initError) | ||
fmt.Println("process: waiting for queries") | ||
for { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for q := range queries {
//got a query
}
//closed
swbemservices.go
Outdated
if s == nil || s.sWbemLocatorIDispatch == nil { | ||
return fmt.Errorf("SWbemServices is not Initialized") | ||
} | ||
if s.queries == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible race condition here. If it closes between the nil check and putting stuff on the channel. I'd make a single lock and you need to acquire it to insert a query or close. Since everything queues up anyway, it shouldn't be a problem.
@captncraig I made the requested changes and added a benchmark. Looks like for a simple query like Win32_OperatingSystem the new method takes ~53ms and the old method takes ~63ms.
|
Haven't found any issues while testing in Scollector, so merged these to master |
I am starting to refactor the WMI/OLE initialization code out of the hot path. I talked with Craig and the current approach is going to be using a channel to send incoming query requests to a dedicated go routine that re-uses the same SWbemServices object instead of creating a new one each time. This should prevent the memory leaks we have seen on Server 2016/Windows 10 and give a good performance boost.
Goals:
go test -run TestWbemMemory -timeout 60m
)Work Items:
Unknowns: