Skip to content

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

Merged
merged 22 commits into from
Nov 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0e93971
Add mutex for sending data via socket.
vladimir-koshelev Oct 12, 2017
dd72860
Add validation to Infos for checking constrains.
vladimir-koshelev Oct 16, 2017
7c57a85
Add `ARG_SCANNER_PREFIX` and `ARG_SCANNER_DEBUG` ENV vars to arg_scanner
vladimir-koshelev Oct 16, 2017
5cdc3e8
Add SignatureViewer tool
vladimir-koshelev Oct 16, 2017
63b26de
Add "*/build/" to gitignore
vladimir-koshelev Oct 16, 2017
6e3adae
Fix commandLine contract server
vladimir-koshelev Oct 16, 2017
f1f11cf
Replace "javafx.util.Pair" to "kotlin.Pair"
vladimir-koshelev Oct 16, 2017
ce86eeb
Remove class name length check from arg_scanner.c
vladimir-koshelev Oct 16, 2017
7c051f4
Refactoring: move db connect calls to DatabaseProvider.
vladimir-koshelev Oct 17, 2017
92e2774
Add SignatureExport to export arg_scanner results to rmc files.
vladimir-koshelev Oct 17, 2017
e1548a6
Add SignatureImport tool.
vladimir-koshelev Oct 18, 2017
b0577cd
Add patchPluginXml section to ide-plugin/build.gradle.
vladimir-koshelev Oct 23, 2017
9354cc6
Rework SignatureViewer. Now it's interactive.
vladimir-koshelev Oct 23, 2017
4759726
RubyStatTypeProvider: use only return types for type inference.
vladimir-koshelev Oct 23, 2017
94bcdf0
Refactor `SignatureInfoSerialization`
vladimir-koshelev Oct 30, 2017
e9d22b3
Refactor `SignatureServer`
vladimir-koshelev Oct 30, 2017
777aa95
Refactor `RubyStatTypeProviderImpl`
vladimir-koshelev Oct 30, 2017
ce3cd0c
Refactor constrains in `ClassInfo`, `GemInfo` and `MethodInfo`
vladimir-koshelev Oct 30, 2017
18d5f68
CallStatCompletionTest change scriptPath to support gradle and ide runs
vladimir-koshelev Nov 2, 2017
0c032d4
Remove unused arguments of `DatabaseProvider#connect`
vladimir-koshelev Nov 2, 2017
1ea6177
Refactor SignatureContract tests
vladimir-koshelev Nov 2, 2017
a9b97e9
proper db setup/teardown in plugin completion test
valich Nov 7, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/build/
out/

*/build/
.gradle

**/.idea/workspace.xml
Expand Down
2 changes: 2 additions & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions arg_scanner/ext/arg_scanner/arg_scanner.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,6 @@ calc_sane_class_name(VALUE ptr)
klass_name = "<err>";
}

if (strlen(klass_name) >= 200)
{
fprintf(stderr, "ERROR: too long class name: '%s'\n", klass_name);
assert(false);
}
return klass_name;
}

Expand Down
71 changes: 66 additions & 5 deletions arg_scanner/lib/arg_scanner/type_tracker.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,53 @@
require 'set'
require 'socket'
require 'singleton'
require 'thread'

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Safe navigation &. FTW
But we'll do it LATER


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

Expand All @@ -13,7 +56,10 @@ class TypeTracker
def initialize
@cache = Set.new
@socket = TCPSocket.new('127.0.0.1', 7777)

@mutex = Mutex.new
Copy link
Collaborator

Choose a reason for hiding this comment

The 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)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw I think @perf_mon = TTPM.new if @enable_debug will do the same :)
But we'll do it LATER

@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
Expand All @@ -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
Expand All @@ -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?
Expand All @@ -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)
Expand Down
8 changes: 5 additions & 3 deletions contract-creator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ sourceSets {
}

dependencies {
compile project(':ruby-call-signature'), project(':storage-server-api')
compile project(':ruby-call-signature')
compile project(':storage-server-api')

compile 'com.h2database:h2:1.4.193'
// compile 'com.h2database:h2:1.4.193'
compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'
}

task runServer(type: JavaExec) {
classpath sourceSets.main.runtimeClasspath
main = 'org.jetbrains.ruby.runtime.signature.server.SignatureServer'
}
}
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
Expand Down Expand Up @@ -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? {
Expand All @@ -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")

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 76
It was used in RubyStatTypeProviderImpl

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 76
I suggest addressing that in another PR in order to increase the possiblity of that one be merged :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 76
Next time, yes, please.

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)
Expand All @@ -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)
}
Expand All @@ -142,7 +165,31 @@ object SignatureServer {
} catch (e: IOException) {
LOGGER.severe("Can't close a socket")
}
onExit(handlerNumber)
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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: ")
Expand Down
5 changes: 5 additions & 0 deletions ide-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ intellij {
plugins = ["org.jetbrains.plugins.ruby:$rubyPluginVersion"]
}

patchPluginXml{
sinceBuild '172.1'
untilBuild '181.*'
}

prepareSandbox.doLast {
def destDir = "$it.destinationDir/$intellij.pluginName"
copy {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.jetbrains.plugins.ruby.ruby.codeInsight

import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.ruby.codeInsight.types.storage.server.DatabaseProvider
import org.jetbrains.ruby.codeInsight.types.storage.server.impl.ClassInfoTable
import org.jetbrains.ruby.codeInsight.types.storage.server.impl.GemInfoTable
import org.jetbrains.ruby.codeInsight.types.storage.server.impl.MethodInfoTable
Expand All @@ -13,10 +13,7 @@ import org.jetbrains.ruby.runtime.signature.server.SignatureServer

class SignatureService {
init {
Database.connect("jdbc:mysql://localhost:3306/" + "ruby_type_contracts" + "?serverTimezone=UTC&nullNamePatternMatchesAll=true&useSSL=false",
driver = "com.mysql.cj.jdbc.Driver",
user = System.getProperty("mysql.user.name", "rubymine"),
password = System.getProperty("mysql.user.password", "rubymine"))
DatabaseProvider.connect()
transaction {
SchemaUtils.create(GemInfoTable, ClassInfoTable, MethodInfoTable, SignatureTable)
}
Expand Down
Loading