1// Copyright 2014, ARM Limited 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are met: 6// 7// * Redistributions of source code must retain the above copyright notice, 8// this list of conditions and the following disclaimer. 9// * Redistributions in binary form must reproduce the above copyright notice, 10// this list of conditions and the following disclaimer in the documentation 11// and/or other materials provided with the distribution. 12// * Neither the name of ARM Limited nor the names of its contributors may be 13// used to endorse or promote products derived from this software without 14// specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27#include "vixl/a64/instrument-a64.h" 28 29namespace vixl { 30 31Counter::Counter(const char* name, CounterType type) 32 : count_(0), enabled_(false), type_(type) { 33 VIXL_ASSERT(name != NULL); 34 strncpy(name_, name, kCounterNameMaxLength); 35} 36 37 38void Counter::Enable() { 39 enabled_ = true; 40} 41 42 43void Counter::Disable() { 44 enabled_ = false; 45} 46 47 48bool Counter::IsEnabled() { 49 return enabled_; 50} 51 52 53void Counter::Increment() { 54 if (enabled_) { 55 count_++; 56 } 57} 58 59 60uint64_t Counter::count() { 61 uint64_t result = count_; 62 if (type_ == Gauge) { 63 // If the counter is a Gauge, reset the count after reading. 64 count_ = 0; 65 } 66 return result; 67} 68 69 70const char* Counter::name() { 71 return name_; 72} 73 74 75CounterType Counter::type() { 76 return type_; 77} 78 79 80struct CounterDescriptor { 81 const char* name; 82 CounterType type; 83}; 84 85 86static const CounterDescriptor kCounterList[] = { 87 {"Instruction", Cumulative}, 88 89 {"Move Immediate", Gauge}, 90 {"Add/Sub DP", Gauge}, 91 {"Logical DP", Gauge}, 92 {"Other Int DP", Gauge}, 93 {"FP DP", Gauge}, 94 95 {"Conditional Select", Gauge}, 96 {"Conditional Compare", Gauge}, 97 98 {"Unconditional Branch", Gauge}, 99 {"Compare and Branch", Gauge}, 100 {"Test and Branch", Gauge}, 101 {"Conditional Branch", Gauge}, 102 103 {"Load Integer", Gauge}, 104 {"Load FP", Gauge}, 105 {"Load Pair", Gauge}, 106 {"Load Literal", Gauge}, 107 108 {"Store Integer", Gauge}, 109 {"Store FP", Gauge}, 110 {"Store Pair", Gauge}, 111 112 {"PC Addressing", Gauge}, 113 {"Other", Gauge}, 114 {"NEON", Gauge}, 115 {"Crypto", Gauge} 116}; 117 118 119Instrument::Instrument(const char* datafile, uint64_t sample_period) 120 : output_stream_(stdout), sample_period_(sample_period) { 121 122 // Set up the output stream. If datafile is non-NULL, use that file. If it 123 // can't be opened, or datafile is NULL, use stdout. 124 if (datafile != NULL) { 125 output_stream_ = fopen(datafile, "w"); 126 if (output_stream_ == NULL) { 127 printf("Can't open output file %s. Using stdout.\n", datafile); 128 output_stream_ = stdout; 129 } 130 } 131 132 static const int num_counters = 133 sizeof(kCounterList) / sizeof(CounterDescriptor); 134 135 // Dump an instrumentation description comment at the top of the file. 136 fprintf(output_stream_, "# counters=%d\n", num_counters); 137 fprintf(output_stream_, "# sample_period=%" PRIu64 "\n", sample_period_); 138 139 // Construct Counter objects from counter description array. 140 for (int i = 0; i < num_counters; i++) { 141 Counter* counter = new Counter(kCounterList[i].name, kCounterList[i].type); 142 counters_.push_back(counter); 143 } 144 145 DumpCounterNames(); 146} 147 148 149Instrument::~Instrument() { 150 // Dump any remaining instruction data to the output file. 151 DumpCounters(); 152 153 // Free all the counter objects. 154 std::list<Counter*>::iterator it; 155 for (it = counters_.begin(); it != counters_.end(); it++) { 156 delete *it; 157 } 158 159 if (output_stream_ != stdout) { 160 fclose(output_stream_); 161 } 162} 163 164 165void Instrument::Update() { 166 // Increment the instruction counter, and dump all counters if a sample period 167 // has elapsed. 168 static Counter* counter = GetCounter("Instruction"); 169 VIXL_ASSERT(counter->type() == Cumulative); 170 counter->Increment(); 171 172 if ((sample_period_ != 0) && counter->IsEnabled() 173 && (counter->count() % sample_period_) == 0) { 174 DumpCounters(); 175 } 176} 177 178 179void Instrument::DumpCounters() { 180 // Iterate through the counter objects, dumping their values to the output 181 // stream. 182 std::list<Counter*>::const_iterator it; 183 for (it = counters_.begin(); it != counters_.end(); it++) { 184 fprintf(output_stream_, "%" PRIu64 ",", (*it)->count()); 185 } 186 fprintf(output_stream_, "\n"); 187 fflush(output_stream_); 188} 189 190 191void Instrument::DumpCounterNames() { 192 // Iterate through the counter objects, dumping the counter names to the 193 // output stream. 194 std::list<Counter*>::const_iterator it; 195 for (it = counters_.begin(); it != counters_.end(); it++) { 196 fprintf(output_stream_, "%s,", (*it)->name()); 197 } 198 fprintf(output_stream_, "\n"); 199 fflush(output_stream_); 200} 201 202 203void Instrument::HandleInstrumentationEvent(unsigned event) { 204 switch (event) { 205 case InstrumentStateEnable: Enable(); break; 206 case InstrumentStateDisable: Disable(); break; 207 default: DumpEventMarker(event); 208 } 209} 210 211 212void Instrument::DumpEventMarker(unsigned marker) { 213 // Dumpan event marker to the output stream as a specially formatted comment 214 // line. 215 static Counter* counter = GetCounter("Instruction"); 216 217 fprintf(output_stream_, "# %c%c @ %" PRId64 "\n", marker & 0xff, 218 (marker >> 8) & 0xff, counter->count()); 219} 220 221 222Counter* Instrument::GetCounter(const char* name) { 223 // Get a Counter object by name from the counter list. 224 std::list<Counter*>::const_iterator it; 225 for (it = counters_.begin(); it != counters_.end(); it++) { 226 if (strcmp((*it)->name(), name) == 0) { 227 return *it; 228 } 229 } 230 231 // A Counter by that name does not exist: print an error message to stderr 232 // and the output file, and exit. 233 static const char* error_message = 234 "# Error: Unknown counter \"%s\". Exiting.\n"; 235 fprintf(stderr, error_message, name); 236 fprintf(output_stream_, error_message, name); 237 exit(1); 238} 239 240 241void Instrument::Enable() { 242 std::list<Counter*>::iterator it; 243 for (it = counters_.begin(); it != counters_.end(); it++) { 244 (*it)->Enable(); 245 } 246} 247 248 249void Instrument::Disable() { 250 std::list<Counter*>::iterator it; 251 for (it = counters_.begin(); it != counters_.end(); it++) { 252 (*it)->Disable(); 253 } 254} 255 256 257void Instrument::VisitPCRelAddressing(const Instruction* instr) { 258 USE(instr); 259 Update(); 260 static Counter* counter = GetCounter("PC Addressing"); 261 counter->Increment(); 262} 263 264 265void Instrument::VisitAddSubImmediate(const Instruction* instr) { 266 USE(instr); 267 Update(); 268 static Counter* counter = GetCounter("Add/Sub DP"); 269 counter->Increment(); 270} 271 272 273void Instrument::VisitLogicalImmediate(const Instruction* instr) { 274 USE(instr); 275 Update(); 276 static Counter* counter = GetCounter("Logical DP"); 277 counter->Increment(); 278} 279 280 281void Instrument::VisitMoveWideImmediate(const Instruction* instr) { 282 Update(); 283 static Counter* counter = GetCounter("Move Immediate"); 284 285 if (instr->IsMovn() && (instr->Rd() == kZeroRegCode)) { 286 unsigned imm = instr->ImmMoveWide(); 287 HandleInstrumentationEvent(imm); 288 } else { 289 counter->Increment(); 290 } 291} 292 293 294void Instrument::VisitBitfield(const Instruction* instr) { 295 USE(instr); 296 Update(); 297 static Counter* counter = GetCounter("Other Int DP"); 298 counter->Increment(); 299} 300 301 302void Instrument::VisitExtract(const Instruction* instr) { 303 USE(instr); 304 Update(); 305 static Counter* counter = GetCounter("Other Int DP"); 306 counter->Increment(); 307} 308 309 310void Instrument::VisitUnconditionalBranch(const Instruction* instr) { 311 USE(instr); 312 Update(); 313 static Counter* counter = GetCounter("Unconditional Branch"); 314 counter->Increment(); 315} 316 317 318void Instrument::VisitUnconditionalBranchToRegister(const Instruction* instr) { 319 USE(instr); 320 Update(); 321 static Counter* counter = GetCounter("Unconditional Branch"); 322 counter->Increment(); 323} 324 325 326void Instrument::VisitCompareBranch(const Instruction* instr) { 327 USE(instr); 328 Update(); 329 static Counter* counter = GetCounter("Compare and Branch"); 330 counter->Increment(); 331} 332 333 334void Instrument::VisitTestBranch(const Instruction* instr) { 335 USE(instr); 336 Update(); 337 static Counter* counter = GetCounter("Test and Branch"); 338 counter->Increment(); 339} 340 341 342void Instrument::VisitConditionalBranch(const Instruction* instr) { 343 USE(instr); 344 Update(); 345 static Counter* counter = GetCounter("Conditional Branch"); 346 counter->Increment(); 347} 348 349 350void Instrument::VisitSystem(const Instruction* instr) { 351 USE(instr); 352 Update(); 353 static Counter* counter = GetCounter("Other"); 354 counter->Increment(); 355} 356 357 358void Instrument::VisitException(const Instruction* instr) { 359 USE(instr); 360 Update(); 361 static Counter* counter = GetCounter("Other"); 362 counter->Increment(); 363} 364 365 366void Instrument::InstrumentLoadStorePair(const Instruction* instr) { 367 static Counter* load_pair_counter = GetCounter("Load Pair"); 368 static Counter* store_pair_counter = GetCounter("Store Pair"); 369 370 if (instr->Mask(LoadStorePairLBit) != 0) { 371 load_pair_counter->Increment(); 372 } else { 373 store_pair_counter->Increment(); 374 } 375} 376 377 378void Instrument::VisitLoadStorePairPostIndex(const Instruction* instr) { 379 Update(); 380 InstrumentLoadStorePair(instr); 381} 382 383 384void Instrument::VisitLoadStorePairOffset(const Instruction* instr) { 385 Update(); 386 InstrumentLoadStorePair(instr); 387} 388 389 390void Instrument::VisitLoadStorePairPreIndex(const Instruction* instr) { 391 Update(); 392 InstrumentLoadStorePair(instr); 393} 394 395 396void Instrument::VisitLoadStorePairNonTemporal(const Instruction* instr) { 397 Update(); 398 InstrumentLoadStorePair(instr); 399} 400 401 402void Instrument::VisitLoadStoreExclusive(const Instruction* instr) { 403 USE(instr); 404 Update(); 405 static Counter* counter = GetCounter("Other"); 406 counter->Increment(); 407} 408 409 410void Instrument::VisitLoadLiteral(const Instruction* instr) { 411 USE(instr); 412 Update(); 413 static Counter* counter = GetCounter("Load Literal"); 414 counter->Increment(); 415} 416 417 418void Instrument::InstrumentLoadStore(const Instruction* instr) { 419 static Counter* load_int_counter = GetCounter("Load Integer"); 420 static Counter* store_int_counter = GetCounter("Store Integer"); 421 static Counter* load_fp_counter = GetCounter("Load FP"); 422 static Counter* store_fp_counter = GetCounter("Store FP"); 423 424 switch (instr->Mask(LoadStoreMask)) { 425 case STRB_w: 426 case STRH_w: 427 case STR_w: 428 VIXL_FALLTHROUGH(); 429 case STR_x: store_int_counter->Increment(); break; 430 case STR_s: 431 VIXL_FALLTHROUGH(); 432 case STR_d: store_fp_counter->Increment(); break; 433 case LDRB_w: 434 case LDRH_w: 435 case LDR_w: 436 case LDR_x: 437 case LDRSB_x: 438 case LDRSH_x: 439 case LDRSW_x: 440 case LDRSB_w: 441 VIXL_FALLTHROUGH(); 442 case LDRSH_w: load_int_counter->Increment(); break; 443 case LDR_s: 444 VIXL_FALLTHROUGH(); 445 case LDR_d: load_fp_counter->Increment(); break; 446 } 447} 448 449 450void Instrument::VisitLoadStoreUnscaledOffset(const Instruction* instr) { 451 Update(); 452 InstrumentLoadStore(instr); 453} 454 455 456void Instrument::VisitLoadStorePostIndex(const Instruction* instr) { 457 USE(instr); 458 Update(); 459 InstrumentLoadStore(instr); 460} 461 462 463void Instrument::VisitLoadStorePreIndex(const Instruction* instr) { 464 Update(); 465 InstrumentLoadStore(instr); 466} 467 468 469void Instrument::VisitLoadStoreRegisterOffset(const Instruction* instr) { 470 Update(); 471 InstrumentLoadStore(instr); 472} 473 474 475void Instrument::VisitLoadStoreUnsignedOffset(const Instruction* instr) { 476 Update(); 477 InstrumentLoadStore(instr); 478} 479 480 481void Instrument::VisitLogicalShifted(const Instruction* instr) { 482 USE(instr); 483 Update(); 484 static Counter* counter = GetCounter("Logical DP"); 485 counter->Increment(); 486} 487 488 489void Instrument::VisitAddSubShifted(const Instruction* instr) { 490 USE(instr); 491 Update(); 492 static Counter* counter = GetCounter("Add/Sub DP"); 493 counter->Increment(); 494} 495 496 497void Instrument::VisitAddSubExtended(const Instruction* instr) { 498 USE(instr); 499 Update(); 500 static Counter* counter = GetCounter("Add/Sub DP"); 501 counter->Increment(); 502} 503 504 505void Instrument::VisitAddSubWithCarry(const Instruction* instr) { 506 USE(instr); 507 Update(); 508 static Counter* counter = GetCounter("Add/Sub DP"); 509 counter->Increment(); 510} 511 512 513void Instrument::VisitConditionalCompareRegister(const Instruction* instr) { 514 USE(instr); 515 Update(); 516 static Counter* counter = GetCounter("Conditional Compare"); 517 counter->Increment(); 518} 519 520 521void Instrument::VisitConditionalCompareImmediate(const Instruction* instr) { 522 USE(instr); 523 Update(); 524 static Counter* counter = GetCounter("Conditional Compare"); 525 counter->Increment(); 526} 527 528 529void Instrument::VisitConditionalSelect(const Instruction* instr) { 530 USE(instr); 531 Update(); 532 static Counter* counter = GetCounter("Conditional Select"); 533 counter->Increment(); 534} 535 536 537void Instrument::VisitDataProcessing1Source(const Instruction* instr) { 538 USE(instr); 539 Update(); 540 static Counter* counter = GetCounter("Other Int DP"); 541 counter->Increment(); 542} 543 544 545void Instrument::VisitDataProcessing2Source(const Instruction* instr) { 546 USE(instr); 547 Update(); 548 static Counter* counter = GetCounter("Other Int DP"); 549 counter->Increment(); 550} 551 552 553void Instrument::VisitDataProcessing3Source(const Instruction* instr) { 554 USE(instr); 555 Update(); 556 static Counter* counter = GetCounter("Other Int DP"); 557 counter->Increment(); 558} 559 560 561void Instrument::VisitFPCompare(const Instruction* instr) { 562 USE(instr); 563 Update(); 564 static Counter* counter = GetCounter("FP DP"); 565 counter->Increment(); 566} 567 568 569void Instrument::VisitFPConditionalCompare(const Instruction* instr) { 570 USE(instr); 571 Update(); 572 static Counter* counter = GetCounter("Conditional Compare"); 573 counter->Increment(); 574} 575 576 577void Instrument::VisitFPConditionalSelect(const Instruction* instr) { 578 USE(instr); 579 Update(); 580 static Counter* counter = GetCounter("Conditional Select"); 581 counter->Increment(); 582} 583 584 585void Instrument::VisitFPImmediate(const Instruction* instr) { 586 USE(instr); 587 Update(); 588 static Counter* counter = GetCounter("FP DP"); 589 counter->Increment(); 590} 591 592 593void Instrument::VisitFPDataProcessing1Source(const Instruction* instr) { 594 USE(instr); 595 Update(); 596 static Counter* counter = GetCounter("FP DP"); 597 counter->Increment(); 598} 599 600 601void Instrument::VisitFPDataProcessing2Source(const Instruction* instr) { 602 USE(instr); 603 Update(); 604 static Counter* counter = GetCounter("FP DP"); 605 counter->Increment(); 606} 607 608 609void Instrument::VisitFPDataProcessing3Source(const Instruction* instr) { 610 USE(instr); 611 Update(); 612 static Counter* counter = GetCounter("FP DP"); 613 counter->Increment(); 614} 615 616 617void Instrument::VisitFPIntegerConvert(const Instruction* instr) { 618 USE(instr); 619 Update(); 620 static Counter* counter = GetCounter("FP DP"); 621 counter->Increment(); 622} 623 624 625void Instrument::VisitFPFixedPointConvert(const Instruction* instr) { 626 USE(instr); 627 Update(); 628 static Counter* counter = GetCounter("FP DP"); 629 counter->Increment(); 630} 631 632 633void Instrument::VisitCrypto2RegSHA(const Instruction* instr) { 634 USE(instr); 635 Update(); 636 static Counter* counter = GetCounter("Crypto"); 637 counter->Increment(); 638} 639 640 641void Instrument::VisitCrypto3RegSHA(const Instruction* instr) { 642 USE(instr); 643 Update(); 644 static Counter* counter = GetCounter("Crypto"); 645 counter->Increment(); 646} 647 648 649void Instrument::VisitCryptoAES(const Instruction* instr) { 650 USE(instr); 651 Update(); 652 static Counter* counter = GetCounter("Crypto"); 653 counter->Increment(); 654} 655 656 657void Instrument::VisitNEON2RegMisc(const Instruction* instr) { 658 USE(instr); 659 Update(); 660 static Counter* counter = GetCounter("NEON"); 661 counter->Increment(); 662} 663 664 665void Instrument::VisitNEON3Same(const Instruction* instr) { 666 USE(instr); 667 Update(); 668 static Counter* counter = GetCounter("NEON"); 669 counter->Increment(); 670} 671 672 673void Instrument::VisitNEON3Different(const Instruction* instr) { 674 USE(instr); 675 Update(); 676 static Counter* counter = GetCounter("NEON"); 677 counter->Increment(); 678} 679 680 681void Instrument::VisitNEONAcrossLanes(const Instruction* instr) { 682 USE(instr); 683 Update(); 684 static Counter* counter = GetCounter("NEON"); 685 counter->Increment(); 686} 687 688 689void Instrument::VisitNEONByIndexedElement(const Instruction* instr) { 690 USE(instr); 691 Update(); 692 static Counter* counter = GetCounter("NEON"); 693 counter->Increment(); 694} 695 696 697void Instrument::VisitNEONCopy(const Instruction* instr) { 698 USE(instr); 699 Update(); 700 static Counter* counter = GetCounter("NEON"); 701 counter->Increment(); 702} 703 704 705void Instrument::VisitNEONExtract(const Instruction* instr) { 706 USE(instr); 707 Update(); 708 static Counter* counter = GetCounter("NEON"); 709 counter->Increment(); 710} 711 712 713void Instrument::VisitNEONLoadStoreMultiStruct(const Instruction* instr) { 714 USE(instr); 715 Update(); 716 static Counter* counter = GetCounter("NEON"); 717 counter->Increment(); 718} 719 720 721void Instrument::VisitNEONLoadStoreMultiStructPostIndex( 722 const Instruction* instr) { 723 USE(instr); 724 Update(); 725 static Counter* counter = GetCounter("NEON"); 726 counter->Increment(); 727} 728 729 730void Instrument::VisitNEONLoadStoreSingleStruct(const Instruction* instr) { 731 USE(instr); 732 Update(); 733 static Counter* counter = GetCounter("NEON"); 734 counter->Increment(); 735} 736 737 738void Instrument::VisitNEONLoadStoreSingleStructPostIndex( 739 const Instruction* instr) { 740 USE(instr); 741 Update(); 742 static Counter* counter = GetCounter("NEON"); 743 counter->Increment(); 744} 745 746 747void Instrument::VisitNEONModifiedImmediate(const Instruction* instr) { 748 USE(instr); 749 Update(); 750 static Counter* counter = GetCounter("NEON"); 751 counter->Increment(); 752} 753 754 755void Instrument::VisitNEONScalar2RegMisc(const Instruction* instr) { 756 USE(instr); 757 Update(); 758 static Counter* counter = GetCounter("NEON"); 759 counter->Increment(); 760} 761 762 763void Instrument::VisitNEONScalar3Diff(const Instruction* instr) { 764 USE(instr); 765 Update(); 766 static Counter* counter = GetCounter("NEON"); 767 counter->Increment(); 768} 769 770 771void Instrument::VisitNEONScalar3Same(const Instruction* instr) { 772 USE(instr); 773 Update(); 774 static Counter* counter = GetCounter("NEON"); 775 counter->Increment(); 776} 777 778 779void Instrument::VisitNEONScalarByIndexedElement(const Instruction* instr) { 780 USE(instr); 781 Update(); 782 static Counter* counter = GetCounter("NEON"); 783 counter->Increment(); 784} 785 786 787void Instrument::VisitNEONScalarCopy(const Instruction* instr) { 788 USE(instr); 789 Update(); 790 static Counter* counter = GetCounter("NEON"); 791 counter->Increment(); 792} 793 794 795void Instrument::VisitNEONScalarPairwise(const Instruction* instr) { 796 USE(instr); 797 Update(); 798 static Counter* counter = GetCounter("NEON"); 799 counter->Increment(); 800} 801 802 803void Instrument::VisitNEONScalarShiftImmediate(const Instruction* instr) { 804 USE(instr); 805 Update(); 806 static Counter* counter = GetCounter("NEON"); 807 counter->Increment(); 808} 809 810 811void Instrument::VisitNEONShiftImmediate(const Instruction* instr) { 812 USE(instr); 813 Update(); 814 static Counter* counter = GetCounter("NEON"); 815 counter->Increment(); 816} 817 818 819void Instrument::VisitNEONTable(const Instruction* instr) { 820 USE(instr); 821 Update(); 822 static Counter* counter = GetCounter("NEON"); 823 counter->Increment(); 824} 825 826 827void Instrument::VisitNEONPerm(const Instruction* instr) { 828 USE(instr); 829 Update(); 830 static Counter* counter = GetCounter("NEON"); 831 counter->Increment(); 832} 833 834 835void Instrument::VisitUnallocated(const Instruction* instr) { 836 USE(instr); 837 Update(); 838 static Counter* counter = GetCounter("Other"); 839 counter->Increment(); 840} 841 842 843void Instrument::VisitUnimplemented(const Instruction* instr) { 844 USE(instr); 845 Update(); 846 static Counter* counter = GetCounter("Other"); 847 counter->Increment(); 848} 849 850 851} // namespace vixl 852