-
Notifications
You must be signed in to change notification settings - Fork 7
Some fixes to run arg_scanner on diaspora specs. #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0e93971
dd72860
7c57a85
5cdc3e8
63b26de
6e3adae
f1f11cf
ce86eeb
7c051f4
92e2774
e1548a6
b0577cd
9354cc6
4759726
94bcdf0
e9d22b3
777aa95
ce3cd0c
18d5f68
0c032d4
1ea6177
a9b97e9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
/build/ | ||
out/ | ||
|
||
*/build/ | ||
.gradle | ||
|
||
**/.idea/workspace.xml | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,53 @@ | ||
require 'set' | ||
require 'socket' | ||
require 'singleton' | ||
require 'thread' | ||
|
||
require_relative 'options' | ||
|
||
module ArgScanner | ||
|
||
class TypeTrackerPerformanceMonitor | ||
def initialize | ||
@enable_debug = ENV["ARG_SCANNER_DEBUG"] | ||
@call_counter = 0 | ||
@handled_call_counter = 0 | ||
@submitted_call_counter = 0 | ||
@old_handled_call_counter = 0 | ||
@time = Time.now | ||
end | ||
|
||
|
||
def on_call | ||
@submitted_call_counter += 1 | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Safe navigation |
||
|
||
def on_return | ||
@call_counter += 1 | ||
|
||
if enable_debug && call_counter % 100000 == 0 | ||
$stderr.puts("calls #{call_counter} handled #{handled_call_counter} submitted #{submitted_call_counter}"\ | ||
"delta #{handled_call_counter - old_handled_call_counter} time #{Time.now - @time}") | ||
@old_handled_call_counter = handled_call_counter | ||
@time = Time.now | ||
end | ||
end | ||
|
||
def on_handled_return | ||
@handled_call_counter += 1 | ||
end | ||
|
||
private | ||
|
||
attr_accessor :submitted_call_counter | ||
attr_accessor :handled_call_counter | ||
attr_accessor :old_handled_call_counter | ||
attr_accessor :call_counter | ||
attr_accessor :enable_debug | ||
|
||
end | ||
|
||
|
||
class TypeTracker | ||
include Singleton | ||
|
||
|
@@ -13,7 +56,10 @@ class TypeTracker | |
def initialize | ||
@cache = Set.new | ||
@socket = TCPSocket.new('127.0.0.1', 7777) | ||
|
||
@mutex = Mutex.new | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest instantiating it only on some condition (debugging env variable, etc) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. btw I think |
||
@prefix = ENV["ARG_SCANNER_PREFIX"] | ||
@enable_debug = ENV["ARG_SCANNER_DEBUG"] | ||
@performance_monitor = if @enable_debug then TypeTrackerPerformanceMonitor.new else nil end | ||
TracePoint.trace(:call, :return) do |tp| | ||
case tp.event | ||
when :call | ||
|
@@ -24,8 +70,13 @@ def initialize | |
end | ||
end | ||
|
||
attr_accessor :enable_debug | ||
attr_accessor :performance_monitor | ||
attr_accessor :cache | ||
attr_accessor :socket | ||
attr_accessor :mutex | ||
attr_accessor :prefix | ||
|
||
|
||
|
||
# @param [String] path | ||
|
@@ -50,20 +101,30 @@ def at_exit | |
end | ||
|
||
def put_to_socket(message) | ||
socket.puts(message) | ||
mutex.synchronize { socket.puts(message) } | ||
end | ||
|
||
private | ||
def handle_call(tp) | ||
#handle_call(VALUE self, VALUE lineno, VALUE method_name, VALUE path) | ||
signature = ArgScanner.handle_call(tp.lineno, tp.method_id, tp.path) | ||
signatures.push(signature) | ||
if prefix.nil? || tp.path.start_with?(prefix) | ||
performance_monitor.on_call unless performance_monitor.nil? | ||
signature = ArgScanner.handle_call(tp.lineno, tp.method_id, tp.path) | ||
signatures.push(signature) | ||
else | ||
signatures.push(false) | ||
end | ||
end | ||
|
||
def handle_return(tp) | ||
sigi = signatures | ||
performance_monitor.on_return unless performance_monitor.nil? | ||
|
||
unless sigi.empty? | ||
signature = sigi.pop | ||
return unless signature | ||
|
||
performance_monitor.on_handled_return unless performance_monitor.nil? | ||
|
||
defined_class = tp.defined_class | ||
return if !defined_class || defined_class.singleton_class? | ||
|
@@ -74,7 +135,7 @@ def handle_return(tp) | |
return if !receiver_name || !receiver_name.to_s || receiver_name.to_s.length > 200 | ||
|
||
json = ArgScanner.handle_return(signature, return_type_name) + | ||
"\"receiver_name\":\"#{receiver_name}\",\"return_type_name\":\"#{return_type_name}\"," | ||
"\"receiver_name\":\"#{receiver_name}\",\"return_type_name\":\"#{return_type_name}\"," | ||
|
||
if cache.add?(json) | ||
gem_name, gem_version = TypeTracker.extract_gem_name_and_version(tp.path) | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -1,11 +1,10 @@ | ||||||||
package org.jetbrains.ruby.runtime.signature.server | ||||||||
|
||||||||
import com.google.gson.JsonParseException | ||||||||
import org.jetbrains.exposed.sql.Database | ||||||||
import org.jetbrains.exposed.sql.SchemaUtils | ||||||||
import org.jetbrains.exposed.sql.transactions.TransactionManager | ||||||||
import org.jetbrains.exposed.sql.transactions.transaction | ||||||||
import org.jetbrains.ruby.codeInsight.types.signature.* | ||||||||
import org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider | ||||||||
import org.jetbrains.ruby.codeInsight.types.storage.server.DiffPreservingStorage | ||||||||
import org.jetbrains.ruby.codeInsight.types.storage.server.RSignatureStorage | ||||||||
import org.jetbrains.ruby.codeInsight.types.storage.server.SignatureStorageImpl | ||||||||
|
@@ -42,11 +41,22 @@ object SignatureServer { | |||||||
@JvmStatic | ||||||||
fun main(args: Array<String>) { | ||||||||
|
||||||||
Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver") | ||||||||
val transaction = TransactionManager.manager.newTransaction() | ||||||||
SchemaUtils.create(GemInfoTable, ClassInfoTable, MethodInfoTable, SignatureTable) | ||||||||
transaction.commit() | ||||||||
runServer() | ||||||||
DatabaseProvider.connect() | ||||||||
|
||||||||
transaction { SchemaUtils.create(GemInfoTable, ClassInfoTable, MethodInfoTable, SignatureTable) } | ||||||||
|
||||||||
Thread { | ||||||||
val server = SignatureServer | ||||||||
while (true) { | ||||||||
try { | ||||||||
server.runServer() | ||||||||
} catch (e: Exception) { | ||||||||
System.err.println(e) | ||||||||
} | ||||||||
|
||||||||
} | ||||||||
|
||||||||
}.start() | ||||||||
} | ||||||||
|
||||||||
fun getContract(info: MethodInfo): SignatureContract? { | ||||||||
|
@@ -57,49 +67,65 @@ object SignatureServer { | |||||||
return getMethodByClass(receiverName, methodName)?.let { mainContainer.getSignature(it)?.contract } | ||||||||
} | ||||||||
|
||||||||
fun getStorage() = mainContainer | ||||||||
|
||||||||
fun getMethodByClass(className: String, methodName: String): MethodInfo? { | ||||||||
return mainContainer.getRegisteredMethods(ClassInfo(className)).find { it.name == methodName } | ||||||||
} | ||||||||
|
||||||||
fun getStorage() = mainContainer | ||||||||
|
||||||||
fun isProcessingRequests() = !isReady.get() | ||||||||
|
||||||||
fun runServer() { | ||||||||
LOGGER.info("Starting server") | ||||||||
|
||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||
SocketDispatcher().start() | ||||||||
|
||||||||
while (true) { | ||||||||
val jsonString = queue.poll(5, TimeUnit.SECONDS) | ||||||||
if (jsonString == null) { | ||||||||
flushNewTuplesToMainStorage() | ||||||||
if (queue.isEmpty()) isReady.set(true) | ||||||||
continue | ||||||||
try { | ||||||||
while (true) { | ||||||||
pollJson() | ||||||||
} | ||||||||
} finally { | ||||||||
LOGGER.warning("Exiting...") | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
try { | ||||||||
val currRTuple = ben(jsonTome) { RTupleBuilder.fromJson(jsonString) } | ||||||||
private fun pollJson() { | ||||||||
val jsonString = queue.poll(5, TimeUnit.SECONDS) | ||||||||
if (jsonString == null) { | ||||||||
flushNewTuplesToMainStorage() | ||||||||
if (queue.isEmpty()) isReady.set(true) | ||||||||
return | ||||||||
} | ||||||||
|
||||||||
if (currRTuple?.methodInfo?.classInfo?.classFQN?.startsWith("#<") == true) { | ||||||||
continue | ||||||||
} | ||||||||
try { | ||||||||
parseJson(jsonString) | ||||||||
} catch (e: JsonParseException) { | ||||||||
LOGGER.severe("!$jsonString!\n$e") | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
ben(addTime) { | ||||||||
if (currRTuple != null | ||||||||
&& !SignatureServer.newSignaturesContainer.acceptTuple(currRTuple) // optimization | ||||||||
&& !SignatureServer.mainContainer.acceptTuple(currRTuple)) { | ||||||||
SignatureServer.newSignaturesContainer.addTuple(currRTuple) | ||||||||
} | ||||||||
} | ||||||||
} catch (e: JsonParseException) { | ||||||||
LOGGER.severe("!$jsonString!\n$e") | ||||||||
private fun parseJson(jsonString: String) { | ||||||||
val currRTuple = ben(jsonTome) { RTupleBuilder.fromJson(jsonString) } | ||||||||
|
||||||||
if (currRTuple?.methodInfo?.classInfo?.classFQN?.startsWith("#<") == true) { | ||||||||
return | ||||||||
} | ||||||||
|
||||||||
ben(addTime) { | ||||||||
if (currRTuple != null | ||||||||
&& !newSignaturesContainer.acceptTuple(currRTuple) // optimization | ||||||||
&& !mainContainer.acceptTuple(currRTuple)) { | ||||||||
newSignaturesContainer.addTuple(currRTuple) | ||||||||
} | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
private fun flushNewTuplesToMainStorage() { | ||||||||
for (methodInfo in newSignaturesContainer.registeredMethods) { | ||||||||
if (!methodInfo.validate()) { | ||||||||
LOGGER.warning("validation failed, cannot store " + methodInfo.toString()) | ||||||||
continue | ||||||||
} | ||||||||
newSignaturesContainer.getSignature(methodInfo)?.let { newSignature -> | ||||||||
transaction { | ||||||||
val storedSignature = mainContainer.getSignature(methodInfo) | ||||||||
|
@@ -124,13 +150,10 @@ object SignatureServer { | |||||||
override fun run() { | ||||||||
try { | ||||||||
val br = BufferedReader(InputStreamReader(socket.getInputStream())) | ||||||||
|
||||||||
while (true) { | ||||||||
onLowQueueCapacity() | ||||||||
val currString = ben(readTime) { br.readLine() } | ||||||||
?: break | ||||||||
if (queue.size > queue.remainingCapacity()) { | ||||||||
LOGGER.info("Queue capacity is low") | ||||||||
} | ||||||||
queue.put(currString) | ||||||||
isReady.set(false) | ||||||||
} | ||||||||
|
@@ -142,7 +165,31 @@ object SignatureServer { | |||||||
} catch (e: IOException) { | ||||||||
LOGGER.severe("Can't close a socket") | ||||||||
} | ||||||||
onExit(handlerNumber) | ||||||||
} | ||||||||
} | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. private? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, thx. |
||||||||
|
||||||||
companion object { | ||||||||
|
||||||||
private var iter = 0L | ||||||||
private var millis = System.currentTimeMillis() | ||||||||
|
||||||||
fun onLowQueueCapacity() { | ||||||||
++iter | ||||||||
val remainingCapacity = queue.remainingCapacity() | ||||||||
val mask = (1L shl 12) - 1L | ||||||||
if (iter and mask == 0L) { | ||||||||
val timeInterval = System.currentTimeMillis() - millis | ||||||||
millis = System.currentTimeMillis() | ||||||||
LOGGER.info( "[" + iter.toString() + "]" +" per second: " + | ||||||||
((mask +1) * 1000 / timeInterval).toString()) | ||||||||
if (queue.size > remainingCapacity) { | ||||||||
LOGGER.info("Queue capacity is low: " + remainingCapacity) | ||||||||
} | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
fun onExit(handlerNumber: Int) { | ||||||||
LOGGER.info("Connection with client# $handlerNumber closed") | ||||||||
|
||||||||
LOGGER.info("Stats: ") | ||||||||
|
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.
ping