blob: 358db994680a5194a76d2cb159313a1c54635bc1 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.lang
import com.intellij.openapi.util.RecursionManager
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import com.intellij.testFramework.IdeaTestUtil
import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.util.ThrowableRunnable
import org.jetbrains.annotations.NotNull
import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor
import org.jetbrains.plugins.groovy.LightGroovyTestCase
import org.jetbrains.plugins.groovy.codeInspection.noReturnMethod.MissingReturnInspection
import org.jetbrains.plugins.groovy.dsl.GroovyDslFileIndex
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager
/**
* @author peter
*/
class GroovyStressPerformanceTest extends LightGroovyTestCase {
final String basePath = ''
@Override
@NotNull
protected LightProjectDescriptor getProjectDescriptor() {
GroovyLightProjectDescriptor.GROOVY_2_3
}
ThrowableRunnable configureAndHighlight(String text) {
return {
myFixture.configureByText 'a.groovy', text
myFixture.doHighlighting()
} as ThrowableRunnable
}
public void testDontWalkLongInferenceChain() throws Exception {
//RecursionManager.assertOnRecursionPrevention(testRootDisposable)
Map<Integer, PsiClass> classes = [:]
myFixture.addFileToProject "Foo0.groovy", """class Foo0 {
def foo() { return 0 }
}"""
def max = 100
for (i in 1..max) {
def file = myFixture.addFileToProject("Foo${i}.groovy", """class Foo$i {
def foo() { return Foo${i - 1}.foo() }
}""")
classes[i] = (file as GroovyFile).classes[0]
}
def deepFile = myFixture.addFileToProject("DeepTest.groovy", "def test() { return Foo${max}.foo() }") as GroovyFile
assert Object.name == inferredType(deepFile.scriptClass, 'test')
def shallowFile = myFixture.addFileToProject("ShallowTest.groovy", "def test() { return Foo2.foo() }") as GroovyFile
assert Integer.name == inferredType(shallowFile.scriptClass, 'test')
int border = (1..max).find { int i ->
GroovyPsiManager.getInstance(project).dropTypesCache()
return inferredType(classes[i], 'foo') == Object.name
}
assert border
GroovyPsiManager.getInstance(project).dropTypesCache()
assert inferredType(classes[border], 'foo') == Object.name
assert inferredType(classes[border - 1], 'foo') == Integer.name
}
private static String inferredType(PsiClass clazz, String method) {
final grMethod = clazz.findMethodsByName(method, false)[0] as GrMethod
grMethod.inferredReturnType.canonicalText
}
public void testQuickIncrementalReparse() {
def story = '''scenario {
given "some precondition", {
// do something
}
when "I do some stuff", {
// foo bar code
}
then "something I expect happens", {
// some verification
}
}
'''
myFixture.configureByText 'a.groovy', story * 200 + "<caret>"
PsiDocumentManager.getInstance(project).commitAllDocuments()
myFixture.type 'foo {}\n'
PsiDocumentManager.getInstance(project).commitAllDocuments()
def start = System.currentTimeMillis()
story.toCharArray().each {
myFixture.type it
PsiDocumentManager.getInstance(project).commitAllDocuments()
}
IdeaTestUtil.assertTiming "slow", 10000, (System.currentTimeMillis() - start)
}
public void testManyAnnotatedFields() {
String text = "class Foo {\n"
for (i in 1..10) {
text += "@Deprecated String foo$i\n"
}
text += "}"
measureHighlighting(text, 5000)
}
private void measureHighlighting(String text, int time) {
IdeaTestUtil.startPerformanceTest("slow", time, configureAndHighlight(text)).cpuBound().usesAllCPUCores().assertTiming()
}
public void testDeeplyNestedClosures() {
RecursionManager.assertOnRecursionPrevention(testRootDisposable)
String text = "println 'hi'"
String defs = ""
for (i in 1..10) {
text = "foo$i { $text }"
defs += "def foo$i(Closure cl) {}\n"
}
myFixture.enableInspections(new MissingReturnInspection())
measureHighlighting(defs + text, 10000)
}
public void testDeeplyNestedClosuresInCompileStatic() {
RecursionManager.assertOnRecursionPrevention(testRootDisposable)
String text = "println 'hi'"
String defs = ""
for (i in 1..10) {
text = "foo$i {a = 5; $text }"
defs += "def foo$i(Closure cl) {}\n"
}
myFixture.enableInspections(new MissingReturnInspection())
addCompileStatic()
measureHighlighting(defs + "\n @groovy.transform.CompileStatic def compiledStatically() {\ndef a = ''\n" + text + "\n}", 10000)
}
public void testDeeplyNestedClosuresInGenericCalls() {
RecursionManager.assertOnRecursionPrevention(testRootDisposable)
String text = "println it"
for (i in 1..10) {
text = "foo(it) { $text }"
}
myFixture.enableInspections(new MissingReturnInspection())
measureHighlighting("def <T> void foo(T t, Closure cl) {}\n$text", 10000)
}
public void testDeeplyNestedClosuresInGenericCalls2() {
RecursionManager.assertOnRecursionPrevention(testRootDisposable)
String text = "println it"
for (i in 1..10) {
text = "foo(it) { $text }"
}
myFixture.enableInspections(new MissingReturnInspection())
measureHighlighting("def <T> void foo(T t, Closure<T> cl) {}\n$text", 10000)
}
public void testManyAnnotatedScriptVariables() {
measureHighlighting((0..100).collect { "@Anno String i$it = null" }.join("\n"), 10000)
}
public void "test no recursion prevention when resolving supertype"() {
RecursionManager.assertOnRecursionPrevention(testRootDisposable)
myFixture.addClass("interface Bar {}")
measureHighlighting("class Foo implements Bar {}", 200)
}
public void "test no recursion prevention when contributing constructors"() {
RecursionManager.assertOnRecursionPrevention(testRootDisposable)
myFixture.addClass("interface Bar {}")
def text = """
@groovy.transform.TupleConstructor
class Foo implements Bar {
int a
Foo b
int getBar() {}
void setBar(int bar) {}
void someMethod(int a = 1) {}
}"""
measureHighlighting(text, 200)
}
public void "test using non-reassigned for loop parameters"() {
RecursionManager.assertOnRecursionPrevention(testRootDisposable)
def text = """
def foo(List<File> list) {
for (file in list) {
${
" println bar(file)\n" * 100
}
}
}
def bar(File file) { file.path }
"""
measureHighlighting(text, 2000)
}
public void "test using SSA variables in a for loop"() {
def text = """
def foo(List<String> list, SomeClass sc) {
List<String> result
for (s in list) {
${
'''
bar(s, result)
bar2(s, result, sc)
bar3(foo:s, bar:result, sc)
sc.someMethod(s)
''' * 100
}
}
}
def bar(String s, List<String> result) { result << s }
def bar2(String s, List<String> result) { result << s }
def bar2(int s, List<String> result, SomeClass sc) { result << s as String }
def bar3(Map args, List<String> result, SomeClass sc) { result << s as String }
class SomeClass {
void someMethod(String s) {}
}
"""
measureHighlighting(text, 8000)
}
public void "test infer only the variable types that are needed"() {
addGdsl '''contribute(currentType(String.name)) {
println 'sleeping'
Thread.sleep(1000)
method name:'foo', type:String, params:[:], namedParams:[
parameter(name:'param1', type:String),
]
}'''
def text = '''
String s = "abc"
while (true) {
s = "str".foo(s)
File f = new File('path')
f.canoPath<caret>
}
'''
IdeaTestUtil.startPerformanceTest("slow", 300, configureAndComplete(text)).cpuBound().usesAllCPUCores().assertTiming()
}
public void testClosureRecursion() {
def text = '''
class AwsService {
def grailsApplication
def configService
def rdsTypeTranslation = [
"udbInstClass.uDBInst" : "db.t1.micro",
"dbInstClass.uDBInst" : "db.t1.micro",
"dbInstClass.smDBInst" : "db.m1.small",
"dbInstClass.medDBInst" : "db.m1.medium",
"dbInstClass.lgDBInst" : "db.m1.large",
"dbInstClass.xlDBInst" : "db.m1.xlarge",
"hiMemDBInstClass.xlDBInst" : "db.m2.xlarge",
"hiMemDBInstClass.xxlDBInst" : "db.m2.2xlarge",
"hiMemDBInstClass.xxxxDBInst" : "db.m2.4xlarge",
"multiAZDBInstClass.uDBInst" : "db.t1.micro",
"multiAZDBInstClass.smDBInst" : "db.m1.small",
"multiAZDBInstClass.medDBInst" : "db.m1.medium",
"multiAZDBInstClass.lgDBInst" : "db.m1.large",
"multiAZDBInstClass.xlDBInst" : "db.m1.xlarge",
"multiAZHiMemInstClass.xlDBInst" : "db.m2.xlarge",
"multiAZHiMemInstClass.xxlDBInst" : "db.m2.2xlarge",
"multiAZHiMemInstClass.xxxxDBInst" : "db.m2.4xlarge"]
def regionTranslation = [
'us-east-1' : 'us-east',
'us-west-2' : 'us-west-2',
'us-west-1' : 'us-west',
'eu-west-1' : 'eu-ireland',
'ap-southeast-1' : 'apac-sin',
'ap-northeast-1' : 'apac-tokyo',
'sa-east-1' : 'sa-east-1']
def price(env) {
def priceMap = [:]
def region = env.region
def aws = new AwsApi(configService.getAwsConfiguration(), env, configService.getTempPath())
def price = 0.0
def count = 0
//def ec2EbsPricing = aws.getEbsOptimizedComputePricing()
def rdsMySqlPricing
def rdsMySqlMultiPricing
def rdsOraclePricing
try {
rdsMySqlPricing = aws.getMySqlPricing()
rdsMySqlMultiPricing = aws.getMySqlMultiAZPricing()
rdsOraclePricing = aws.getOracleLIPricing()
} catch (Exception) {
//TODO : Find new rds pricing json
}
//def elbPricing = aws.getELBPricing()
def ebsPricing = aws.getEBSPricing()
aws.getComputeResponse(region).reservations.each { Reservation inst ->
inst.instances.each { Instance it ->
if (it.state.code.toInteger() == 16) {
def os
switch (it.platform) {
case 'windows':
os = "mswin"
break;
case 'linux':
default:
os = "linux"
break;
}
aws.getComputePricing(os).config.regions.each { pricingRegion ->
if (pricingRegion.region == regionTranslation[region]) {
pricingRegion.instanceTypes.each { instanceType ->
instanceType.sizes.each { size ->
if (size.size == it.instanceType) {
size.valueColumns.each { valueColumn ->
if (valueColumn.name == os) {
//Price by type
def key = "price-ec2-" + os + "-" + it.instanceType
if (!priceMap.containsKey(key)){
priceMap[key] = 0.0
}
priceMap[key] += valueColumn.prices.USD.toFloat()
//Type count
key = "count-ec2-" + os + "-" + it.instanceType
if (!priceMap.containsKey(key)){
priceMap[key] = 0
}
priceMap[key] += 1
count++
//Price for all
if (!priceMap.containsKey("price-ec2")){
priceMap["price-ec2"] = 0.0
}
priceMap["price-ec2"] += valueColumn.prices.USD.toFloat()
//Total
price += valueColumn.prices.USD.toFloat()
}
}
}
}
}
}
}
}
}
}
def rdsPrice = 0.0
aws.getRDSResponse(region).dBInstances.each { DBInstance it ->
def json
switch (it.engine) {
case 'mysql':
if (it.multiAZ) {
json = rdsMySqlMultiPricing
} else {
json = rdsMySqlPricing
}
break;
case 'oracle-se1':
json = rdsOraclePricing
break;
}
if (json != null) {
json.config.regions.each { pricingRegion ->
if (pricingRegion.region == regionTranslation[region]) {
pricingRegion.types.each { instanceType ->
instanceType.tiers.each { tier ->
if (rdsTypeTranslation[instanceType.name + "." + tier.name] == it.DBInstanceClass) {
rdsPrice += tier.prices.USD.toFloat()
price += tier.prices.USD.toFloat()
}
}
}
}
}
}
}
//TODO : IOPS
def ebsPrice = 0.0
aws.getEBSResponse(region).volumes.each { Volume it ->
ebsPricing.config.regions.each { pricingRegion ->
if (pricingRegion.region == regionTranslation[region]) {
pricingRegion.types.each { ebsType ->
if (ebsType.name == "ebsVols") {
ebsType.values.each { ebsValue ->
if (ebsValue.rate == "perGBmoProvStorage") {
ebsPrice += (ebsValue.prices.USD.toFloat() * it.size.toFloat() / 30 / 24)
price += (ebsValue.prices.USD.toFloat() * it.size.toFloat() / 30 / 24)
}
}
}
}
}
}
}
priceMap.put("price-total", price)
priceMap.put("price-rds", rdsPrice)
priceMap.put("price-ebs", ebsPrice)
priceMap.put("count-total", count)
return priceMap
}
}
'''
measureHighlighting(text, 1000)
}
ThrowableRunnable configureAndComplete(String text) {
return {
myFixture.configureByText 'a.groovy', text
myFixture.completeBasic()
} as ThrowableRunnable
}
private def addGdsl(String text) {
final PsiFile file = myFixture.addFileToProject("Enhancer.gdsl", text)
GroovyDslFileIndex.activateUntilModification(file.virtualFile)
}
}